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
.ps
is a type-level list of parties participating in the choreography,m
is an monad used to write local actions those parties can take (often this is simplyIO
),a
is the returned value, typically this will be aLocated
orFaceted
value 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 enclaves, and multiply-located values to achieve excellent expressivity and efficient Knowledge of Choice management.
- A value of type
Located ls a
is a singlea
known 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 senders
sends the valuev
to all of the recipients inrs
, resulting in aLocated rs v
. - For easy branching in choreographies, the primitives
enclave
andnaked
combine to formcond
.(parties, guard) `cond` (\g -> c)
unwraps aLocated parties g
for use as a nakedg
in 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 aString
or 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:
fanOut
lets a single party send different values (of the same typea
) to a list of partiesrs
, resulting in aFaceted rs a
.fanIn
lets a list of partiesss
each send a value to the same partiesrs
, resulting in aLocated rs (Quire ss a)
.- A
x :: Faceted ps qs a
represents distincta
s known to each ofps
respectively; the parties inqs
know all thea
s.
- MultiChor allows parallel behavior of many parties to be concisely expressed.
parallel
lets many parties perform local monadic actions in parallel using theirLocated
andFaceted
values; the return isFaceted
.congruently
lets many parties perform the same pure computation in parallel, using only theirLocated
values; 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 -l
to 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.