MultiChor is a library for writing choreographic programs in Haskell.
That means you write one program, a "choreography" which seamlessly describes the actions of many communicating machines; these participants can be native Haskell threads, or various humans' laptops communicating over HTTPS, or anything in between. Each of these "endpoints" will "project" their behavior out of the choreography.
Choreographies aren't just easier to write than distributed programs, they're automatically deadlock-free!
MultiChor uses some of the same conventions and internal machinery as HasChor, but the API is incompatible and can express more kinds of choreographic behavior.
- The heart of the MultiChor library is a choreography monad
Choreo ps m a.psis a type-level list of parties participating in the choreography,mis an monad used to write local actions those parties can take (often this is simplyIO),ais the returned value, typically this will be aLocatedorFacetedvalue as described below.
- MultiChor is an embedded DSL, as interoperable with the rest of the Haskell ecosystem as any other monad. In particular, MultiChor gets recursion, polymorphism, and location-polymorphism "for free" as features of Haskell!
- MultiChor uses conclaves, and multiply-located values to achieve excellent expressivity and efficient Knowledge of Choice management.
- A value of type
Located ls ais a singleaknown to all the parties listed inls. In a well-typed choreography, other parties, who may not know thea, will never attempt to use it. - In the expression
(s, v) ~> rs, a senderssends the valuevto all of the recipients inrs, resulting in aLocated rs v. - For easy branching in choreographies, the primitives
conclaveandnakedcombine to formcond.(parties, guard) `cond` (\g -> c)unwraps aLocated parties gfor use as a nakedgin the conditional choreographyc.
- A value of type
- Safe handing of parties, party-sets, and located values is enforced using term-level proof objects.
In particular, instead of specifying the party
"alice"in a choreography as aStringor aProxy "alice", they're specified by a "proof" that the type-level"alice"is present in the choreography and has access to the relevant values. MultiChor provides utilities to write these proofs compactly. - In addition to location polymorphism, MultiChor allows you to write choreographies
that are polymorphic with respect to the number of parties in a polymorphic party-set.
This is trivial if they're passively receiving values; new functions allow them to actively communicate:
fanOutlets a single party send different values (of the same typea) to a list of partiesrs, resulting in aFaceted rs a.fanInlets a list of partiessseach send a value to the same partiesrs, resulting in aLocated rs (Quire ss a).- A
x :: Faceted ps qs arepresents distinctas known to each ofpsrespectively; the parties inqsknow all theas.
- MultiChor allows parallel behavior of many parties to be concisely expressed.
parallellets many parties perform local monadic actions in parallel using theirLocatedandFacetedvalues; the return isFaceted.congruentlylets many parties perform the same pure computation in parallel, using only theirLocatedvalues; the return isLocated.
Unit test can and should be run frequently with cabal test -f test.
(The flag test is required to expose the contents of the examples dir.)
We use hlint and ormolu, both of which are free and default with hls.
At present these are not set up to run automatically.
Run hlint src --report to check for hints.
Run
ormolu --mode check $(git ls-files '*.hs') 2>&1 | wc -lto check for unformatted files; if you're all set then it will just print 0.
You should also run cabal check, to detect any less common config issues,
and inspect the output of cabal haddock for any warnings.
Many example choreographies are presented in the examples directory.
Cabal will ignore them unless provided with the -f test flag.