monad-embed makes writing code that uses monads as easy as writing pure code. It makes `do`

-notation unnecessary in many cases. It makes `sequence`

, `liftM`

, and some other functions unnecessary.

Because functions in monad-embed are parameterized on an arbitrary monad by default, functions like `mapM`

and `filterM`

are unnecessary. Haskell offers monadic versions only of common functions such as `map`

, `filter`

, and `foldl`

; when a programmer needs a monadic version of another function, they must write one for themself. More often, they write a manual solution. This reduces code reuse.

For example, consider the following code fragment from a hypothetical compiler:

import Data.Map processFuns :: Map String Fun -> Map String Fun2 processFuns = Data.Map.updateWithKey processFun processFun :: String -> Fun -> Maybe Fun2 processFun = ...

This is all well and good until the programmer wants to use the `Either`

monad to report errors that occur in `processFun`

:

processFun :: String -> Fun -> Either ErrorMessage (Maybe Fun2)

Unfortunately, `Data.Map`

does not define `updateWithKeyM`

. The programmer must define it for themself:

updateWithKeyM f m = liftM (fromList . concat) $ sequence [do mv <- f k v case mv of Nothing -> return [] Just v' -> return [(k, v')] | (k, v) <- toList m];

This is inconvenient. monad-embed solves this problem by making every function work with any monad by default. If `Data.Map`

were ported to monad-embed, the functions it defines would work with any monad without any extra effort on the part of the programmer.

A final reason to use monad-embed is that parameterizing an entire program on an underlying monad opens up new ways of using monads.

For example, a programmer trying to debug a complicated library might temporarily instantiate their entire library in the `IO`

monad to allow them to write debugging output to a file, much as programmers in imperative languages temporary add `print`

calls when trying to track down bugs. This would work without using `unsafePerformIO`

or `Debug.Trace`

to write debugging information.

For example, consider this implementation of quicksort:

sort :: (f :: * -> *, a :: *) => {f} (a -> a -> Ordering) -> List a -> List a; sort = \ cmp list -> case list of { Nil -> Nil; Cons x xs -> do { greaterThanX = y -> cmp x y `equalOrdering` GT } then sort cmp (filter greaterThanX xs) `cat` (x `Cons` Nil) `cat` sort cmp (filter (not `compose` greaterThanX) xs); };This is equivalent to the normal Haskell definition of quicksort, but parameterized on a comparison function. It is verbose because of monad-embed's poor standard library and parser.

We can instrument this to print a message every time we compare two numbers without changing the definition of `sort`

at all; we only need to define our own comparision function:

printAndCompare :: {IO} Number -> Number -> Ordering; printAndCompare = \ x y -> do { output ("Comparing " `strCat` numToStr x `strCat` " to " `strCat` numToStr y); } then compareNumbers x y; exampleList = 4 `Cons` 333 `Cons` -2 `Cons` 84 `Cons` -2 `Cons` Nil; main = do { output "Sorting numbers..."; nums <- sort printAndCompare exampleList; output "Sorted numbers are:"; } then outputNumbers nums;

The output of this program is:

Output: Sorting numbers... Output: Comparing 4.0 to 333.0 Output: Comparing 4.0 to -2.0 Output: Comparing 4.0 to 84.0 Output: Comparing 4.0 to -2.0 Output: Comparing -2.0 to -2.0 Output: Comparing -2.0 to -2.0 Output: Comparing 4.0 to 333.0 Output: Comparing 4.0 to -2.0 Output: Comparing 4.0 to 84.0 Output: Comparing 4.0 to -2.0 Output: Comparing 333.0 to 84.0 Output: Comparing 333.0 to 84.0 Output: Sorted numbers are: Output: -2.0 Output: -2.0 Output: 4.0 Output: 84.0 Output: 333.0