This tutorial will assume you already know Haskell; it will skip the basics and go straight to the parts of monad-embed that are different from Haskell.

It will also assume you have already read the syntax section, or that you can pick up the syntax as you go along.

Every term in monad-embed has two types associated with it: its *type*, of kind `*`

, and its *flavor*, which is a monad of kind `* -> *`

. Type and flavor are often written together using the syntax `{flavor} type`

. The reduction of the term is described in terms of the `return`

and `(>>=)`

operations of its flavor. The details of the reduction process are here.

`wrap`

and `unwrap`

The built-in `wrap`

and `unwrap`

functions in monad-embed move monad-transformers between an expression's type and its flavor.

`wrap`

takes a value of type and flavor `{m} (t m a)`

, where `m`

is a monad and `t`

is a monad transformer. It moves the `t`

transformer from the expression's type to its flavor; the return value of wrap has type and flavor `{t / m} a`

, where `/`

indicates the composition of a monad transformer with a monad.

`unwrap`

does the exact opposite of `wrap`

. It takes a value of type and flavor `{t / m} a`

, and produces a value of type and flavor `{m} (t m a)`

.

`wrap`

In general, `wrap`

is used to create side effects. You construct a value of type `t m a`

which describes the side effects, and then you use `wrap`

to convert from a term that explicitly describes the side effects to a term that implicly has the side effects.

For example, suppose that we are using the `ZList`

monad transformer, which is similar to Haskell's `ListT`

. We can use the following code to create a definition that is simultaneously equal to `1`

and `2`

:

oneOrTwo :: (m :: * -> *) => {ZList / m} Number; oneOrTwo = wrap [ZCons 1 [ZCons 2 [ZNil]]];

`oneOrTwo`

has type `Number`

, but because its flavor is `ZList / m`

, it is internally actually a list of numbers. We use `wrap`

to convert from `ZCons 1 [ZCons 2 [ZNil]]`

, which has type and flavor `{m} ZList m Number`

, to `oneOrTwo`

.
We can then use `oneOrTwo`

in other functions in the `ZList`

monad transformer. For example:

pairsOfOneAndTwo :: (m :: * -> *) => {ZList / m} Pair Number Number; pairsOfOneAndTwo = Pair oneOrTwo oneOrTwo;Internally,

`pairsOfOneAndTwo`

is a list of four values: `(Pair 1 1)`

, `(Pair 1 2)`

, `(Pair 2 1)`

, and `(Pair 2 2)`

. If we wanted to just have `(Pair 1 1)`

and `(Pair 2 2)`

, we could write this instead:pairOfOneOrTwo :: (m :: * -> *) => {ZList / m} Pair Number Number; pairOfOneOrTwo = do { x = oneOrTwo; } then Pair x x;

`unwrap`

Terms that are internally monadic aren't any good if you can't access the internal monad. The `unwrap`

function converts terms of type and flavor `{t / m} a`

into terms of type and flavor `{m} (t m a)`

, allowing you to work with the internal monad. For example, suppose that we want to write a program that prints every pair in `pairsOfOneAndTwo`

to the console:

printPairs :: {IO} ZList IO (Pair Number Number) -> Unit; printPairs = \ pairs -> case pairs of { ZNil -> Unit; ZCons (Pair a b) [rest] -> do { output (numToStr a `strCat` ", " `strCat` numToStr b); } then printPairs rest; }; main = printPairs (unwrap [pairsOfOneAndTwo]);The output from this program is:

Output: 1.0, 1.0 Output: 1.0, 2.0 Output: 2.0, 1.0 Output: 2.0, 2.0

`oneOrTwo`

, `pairsOfOneAndTwo`

, and `pairOfOneOrTwo`

are all polymorphic on a monad `m`

. In this example program, `m`

is always instantiated to `IO`

, but this isn't necessary. `oneOrTwo`

and its friends could be used in a function that was itself embedded in another monad on top of `IO`

.

As an example of this, consider a slightly more useful function than `oneOrTwo`

: `either`

. The function `either`

, which is defined in the standard library, takes two arguments of the same type and returns both of them. Of course, this is only possible because it exists in the `ZList`

monad. `either`

is defined as follows:

either :: (f :: * -> *, a :: *) => {ZList / f} [a] -> [a] -> a; either = \ [x] [y] -> wrap [zcat (unwrap [x]) [unwrap [y]]];The square brackets

`[]`

indicate that the function arguments are passed lazily. (There is no syntactic sugar for lists in monad-embed.) `either`

works by `unwrap`

ping both of its arguments into `ZList`

s, concatenating the two lists, and then re-`wrap`

ping the concatenated `ZList`

s. We could have defined `oneOrTwo`

as `either [1] [2]`

.
`either`

only works in the `ZList`

monad transformer, but it works with any monad under `ZList`

. The following contrived example uses the `State`

monad transformer to sum the alternatives produced by an expression using `either`

:

oneTwoThreeFour :: (f :: * -> *) => {ZList / f} Number; oneTwoThreeFour = either [1] [either [2] [either [3] [4]]]; sumNumbers :: (g :: * -> *) => {State Number / g} Unit; sumNumbers = do { numbers = lazyToStrictList (unwrap [oneTwoThreeFour]); map (num -> setState (getState `plus` num)) numbers; } then Unit; main = do { sum = fst (runState 0 (unwrap [sumNumbers])); outputNumber sum; } then Unit;In

`sumNumbers`

, `g`

is instantiated to `IO`

. In `oneTwoThreeFour`

, `f`

is instantiated to `State Number / IO`

.
In Haskell, side effects are very limited. Besides `unsafePerformIO`

, the side effects of a function are limited to nontermination and raising exceptions via `error`

. In monad-embed, side effects can be anything that can be expressed in the monad that is the flavor of the term. In order to give the programmer more control of exactly when side effects are executed, monad-embed offers strict and lazy variations on functions, `do`

-bindings, and data constructor fields.

A strict function's argument is evaluated exactly once, when the function is called. A lazy function's argument may be evaluated zero or any number of times, depending on how the function uses its argument. Lazy functions obey beta-reduction, but strict functions do not.

fooStrict :: {IO} Unit -> Unit; fooStrict = \ x -> do { x; x; x; } then Unit; fooLazy :: {IO} [Unit] -> Unit; fooLazy = \ [x] -> do { x; x; x; } then Unit; -- Outputs "hello" once and "goodbye" three times main = do { fooStrict (output "hello"); fooLazy [output "goodbye"]; } then Unit;

Strict and lazy data fields are similar. A strict data field is evaluated once, when the constructor is called; in a lazy data field, the side-effects are "preserved" in the data structure and "replayed" wherever it is used. For example:

data Test (f :: * -> *) = { Test -- Constructor with two fields [{f} Unit] -- This one is lazy Unit; -- This one is strict }; main = do { thing = Test [output "foo"] (output "bar"); -- Outputs "bar" output "***"; case thing of { Test [a] b -> do { a; -- Outputs "foo" b; -- Does not output anything } then Unit; }; } then Unit;

Strict and lazy `do`

-bindings work similarly.

Note that a variable introduced into scope by a strict function, strict pattern match, or strict `do`

-binding can take on any flavor at the point that it is used, whereas a variable introduced into scope by a lazy function, lazy pattern match, or lazy `do`

-binding has a specific flavor.

monad-embed does not have any user-defined monads. The only monads in monad-embed are the `IO`

monad and monads formed by the `/`

operator from another monad and a monad transformer. Instead of allowing the user to define new monads, monad-embed allows the user to define new monad transformers.

New monad transformers are defined using the `transformer`

keyword:

transformer Constructor (field :: kind) ... where { return = ...; bind = ...; };

The `return`

function should have type

(m :: * -> *, a :: *) => {m} a -> t m awhere

`t`

is the transformer. The `bind`

function should have type (m :: * -> *, a :: *, b :: *) => {m} t m a -> (a -> t m b) -> t m b

For example, the `ZList`

monad transformer, which is equivalent to Haskell's `ListT`

done right, is defined as follows:

data ZList (f :: * -> *) (a :: *) = { ZNil; ZCons a [{f} ZList f a]; -- Tail is lazy; that's why it's called ZList }; transformer ZList where { return = \ x -> ZCons x [ZNil]; bind = \ x f -> zconcat (zmap f x); };

One interesting thing to notice about this definition is that it looks more like the Haskell List monad than any Haskell monad transformer. The `ZList`

monad transformer never mentions the `return`

or `bind`

operations of the monad that it is parameterized on. Instead, they are used implicitly because `return`

and `bind`

have the flavor of the monad that `ZList`

is parameterized on. (I suspect, but have not proven, that this produces valid monad transformers.)