This source repository contains the implementation of joinads for the Haskell language. The design of the extension is described in a paper Extending Monads with Pattern Matching, which provides more details about the langauge extension and gives numerous examples.
The language extension adds
docase construct to Haskell. Similarly to the
the construct can be used with any type that provides instance for a certain type class.
In case of
do, the type class is
Monad. To support
docase, type must implement a
Joinad type cass that extends
Monad with three additional operators that represent
non-deterministic choice between computations, parallel composition of computations
and aliasing of computations).
The following example uses the instance for the
Par monad. It implements a function
that recursively processes a tree and returns
True when the tree contains element that
matches the specified predicate:
all :: (a -> Bool) -> Tree a -> Par Bool all p (Leaf v) = return (p v) all p (Node left right) = docase (all p left, all p right) of (False, ?) -> return False (?, False) -> return False (allL, allR) -> return (allL && allR)
docase syntax is similar to pattern matching using
case, but works on monadic computations.
The monadic computation
Par a represents a task that can be executed (using a parallel scheduler)
and eventually returns a value of type
In the above example, the
docase construct creates a computation that starts processing
left and right sub-trees in parallel. When any of the sub-tasks completes and returns
we already know that the overall result will be
False, so we don't need to wait for the
completion of the second task. This expressed using the
? pattern in the first and the
second clause. Finally, the last clause handles the case when we need to wait for both of the
values before producing the result.
docase extension is currently implemented using a pre-processor that takes Haskell'98
code with the
docase extension and translates it into standard Haskell'98 source (it replaces
docase with calls to standard functions). The pre-processor is based on the pre-processor
for arrow syntax implemented by Ross Paterson.
Preprocessor directory contains the implementation of the pre-processor. It can be compiled using the
Makefileprovided and then executed using the command:
joinadsp.exe Sample.jhs > Sample.hs
Samples includes numerous examples that use joinads. It includes
Joinadinstance for the
Maybetype and types mentioned in the paper (parsers that can be used for input validation, parallelsim monad used above and simple cooperative parallelism monad using resumptions).
ParMonad includes core parts of the
Parmonad that is used in the parallel programming samples. The implementation is extended to support speculative parallelism (see a separate a blog post). a complete modified implementation is available in a separate project
Comprehensions shows several examples that use generalized zip comprehensions (or parallel monad comprehensions) to write similar examples as those that use
docasenotation. Zip comprehensions are a generalization of parallel list comprehensions and overlap with joinads. For more information see an article in The Monad.Reader Issue 18.