<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ --> <title>Control/Monad/Morph.hs</title> <link type='text/css' rel='stylesheet' href='hscolour.css' /> </head> <body> <pre><a name="line-1"></a><span class='hs-comment'>{-| A monad morphism is a natural transformation: <a name="line-2"></a> <a name="line-3"></a>> morph :: forall a . m a -> n a <a name="line-4"></a> <a name="line-5"></a> ... that obeys the following two laws: <a name="line-6"></a> <a name="line-7"></a>> morph $ do x <- m = do x <- morph m <a name="line-8"></a>> f x morph (f x) <a name="line-9"></a>> <a name="line-10"></a>> morph (return x) = return x <a name="line-11"></a> <a name="line-12"></a> ... which are equivalent to the following two functor laws: <a name="line-13"></a> <a name="line-14"></a>> morph . (f >=> g) = morph . f >=> morph . g <a name="line-15"></a>> <a name="line-16"></a>> morph . return = return <a name="line-17"></a> <a name="line-18"></a> Examples of monad morphisms include: <a name="line-19"></a> <a name="line-20"></a> * 'lift' (from 'MonadTrans') <a name="line-21"></a> <a name="line-22"></a> * 'squash' (See below) <a name="line-23"></a> <a name="line-24"></a> * @'hoist' f@ (See below), if @f@ is a monad morphism <a name="line-25"></a> <a name="line-26"></a> * @(f . g)@, if @f@ and @g@ are both monad morphisms <a name="line-27"></a> <a name="line-28"></a> * 'id' <a name="line-29"></a> <a name="line-30"></a> Monad morphisms commonly arise when manipulating existing monad transformer <a name="line-31"></a> code for compatibility purposes. The 'MFunctor', 'MonadTrans', and <a name="line-32"></a> 'MMonad' classes define standard ways to change monad transformer stacks: <a name="line-33"></a> <a name="line-34"></a> * 'lift' introduces a new monad transformer layer of any type. <a name="line-35"></a> <a name="line-36"></a> * 'squash' flattens two identical monad transformer layers into a single <a name="line-37"></a> layer of the same type. <a name="line-38"></a> <a name="line-39"></a> * 'hoist' maps monad morphisms to modify deeper layers of the monad <a name="line-40"></a> transformer stack. <a name="line-41"></a> <a name="line-42"></a>-}</span> <a name="line-43"></a> <a name="line-44"></a><span class='hs-comment'>{-# LANGUAGE Rank2Types #-}</span> <a name="line-45"></a> <a name="line-46"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span><span class='hs-varop'>.</span><span class='hs-conid'>Morph</span> <span class='hs-layout'>(</span> <a name="line-47"></a> <span class='hs-comment'>-- * Functors over Monads</span> <a name="line-48"></a> <span class='hs-conid'>MFunctor</span><span class='hs-layout'>(</span><span class='hs-keyglyph'>..</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span> <a name="line-49"></a> <span class='hs-comment'>-- * Monads over Monads</span> <a name="line-50"></a> <span class='hs-conid'>MMonad</span><span class='hs-layout'>(</span><span class='hs-keyglyph'>..</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span> <a name="line-51"></a> <span class='hs-conid'>MonadTrans</span><span class='hs-layout'>(</span><span class='hs-varid'>lift</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span> <a name="line-52"></a> <span class='hs-varid'>squash</span><span class='hs-layout'>,</span> <a name="line-53"></a> <span class='hs-layout'>(</span><span class='hs-varop'>>|></span><span class='hs-layout'>)</span><span class='hs-layout'>,</span> <a name="line-54"></a> <span class='hs-layout'>(</span><span class='hs-varop'><|<</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span> <a name="line-55"></a> <span class='hs-layout'>(</span><span class='hs-varop'>=<|</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span> <a name="line-56"></a> <span class='hs-layout'>(</span><span class='hs-varop'>|>=</span><span class='hs-layout'>)</span> <a name="line-57"></a> <a name="line-58"></a> <span class='hs-comment'>-- * Tutorial</span> <a name="line-59"></a> <span class='hs-comment'>-- $tutorial</span> <a name="line-60"></a> <a name="line-61"></a> <span class='hs-comment'>-- ** Generalizing base monads</span> <a name="line-62"></a> <span class='hs-comment'>-- $generalize</span> <a name="line-63"></a> <a name="line-64"></a> <span class='hs-comment'>-- ** Monad morphisms</span> <a name="line-65"></a> <span class='hs-comment'>-- $mmorph</span> <a name="line-66"></a> <a name="line-67"></a> <span class='hs-comment'>-- ** Mixing diverse transformers</span> <a name="line-68"></a> <span class='hs-comment'>-- $interleave</span> <a name="line-69"></a> <a name="line-70"></a> <span class='hs-comment'>-- ** Embedding transformers</span> <a name="line-71"></a> <span class='hs-comment'>-- $embed</span> <a name="line-72"></a> <span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-73"></a> <a name="line-74"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span><span class='hs-varop'>.</span><span class='hs-conid'>Trans</span><span class='hs-varop'>.</span><span class='hs-conid'>Class</span> <span class='hs-layout'>(</span><span class='hs-conid'>MonadTrans</span><span class='hs-layout'>(</span><span class='hs-varid'>lift</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-75"></a><span class='hs-keyword'>import</span> <span class='hs-keyword'>qualified</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span><span class='hs-varop'>.</span><span class='hs-conid'>Trans</span><span class='hs-varop'>.</span><span class='hs-conid'>Error</span> <span class='hs-keyword'>as</span> <span class='hs-conid'>E</span> <a name="line-76"></a><span class='hs-keyword'>import</span> <span class='hs-keyword'>qualified</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span><span class='hs-varop'>.</span><span class='hs-conid'>Trans</span><span class='hs-varop'>.</span><span class='hs-conid'>Identity</span> <span class='hs-keyword'>as</span> <span class='hs-conid'>I</span> <a name="line-77"></a><span class='hs-keyword'>import</span> <span class='hs-keyword'>qualified</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span><span class='hs-varop'>.</span><span class='hs-conid'>Trans</span><span class='hs-varop'>.</span><span class='hs-conid'>Maybe</span> <span class='hs-keyword'>as</span> <span class='hs-conid'>M</span> <a name="line-78"></a><span class='hs-keyword'>import</span> <span class='hs-keyword'>qualified</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span><span class='hs-varop'>.</span><span class='hs-conid'>Trans</span><span class='hs-varop'>.</span><span class='hs-conid'>Reader</span> <span class='hs-keyword'>as</span> <span class='hs-conid'>R</span> <a name="line-79"></a><span class='hs-keyword'>import</span> <span class='hs-keyword'>qualified</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span><span class='hs-varop'>.</span><span class='hs-conid'>Trans</span><span class='hs-varop'>.</span><span class='hs-conid'>RWS</span><span class='hs-varop'>.</span><span class='hs-conid'>Lazy</span> <span class='hs-keyword'>as</span> <span class='hs-conid'>RWS</span> <a name="line-80"></a><span class='hs-keyword'>import</span> <span class='hs-keyword'>qualified</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span><span class='hs-varop'>.</span><span class='hs-conid'>Trans</span><span class='hs-varop'>.</span><span class='hs-conid'>RWS</span><span class='hs-varop'>.</span><span class='hs-conid'>Strict</span> <span class='hs-keyword'>as</span> <span class='hs-conid'>RWS'</span> <a name="line-81"></a><span class='hs-keyword'>import</span> <span class='hs-keyword'>qualified</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span><span class='hs-varop'>.</span><span class='hs-conid'>Trans</span><span class='hs-varop'>.</span><span class='hs-conid'>State</span><span class='hs-varop'>.</span><span class='hs-conid'>Lazy</span> <span class='hs-keyword'>as</span> <span class='hs-conid'>S</span> <a name="line-82"></a><span class='hs-keyword'>import</span> <span class='hs-keyword'>qualified</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span><span class='hs-varop'>.</span><span class='hs-conid'>Trans</span><span class='hs-varop'>.</span><span class='hs-conid'>State</span><span class='hs-varop'>.</span><span class='hs-conid'>Strict</span> <span class='hs-keyword'>as</span> <span class='hs-conid'>S'</span> <a name="line-83"></a><span class='hs-keyword'>import</span> <span class='hs-keyword'>qualified</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span><span class='hs-varop'>.</span><span class='hs-conid'>Trans</span><span class='hs-varop'>.</span><span class='hs-conid'>Writer</span><span class='hs-varop'>.</span><span class='hs-conid'>Lazy</span> <span class='hs-keyword'>as</span> <span class='hs-conid'>W'</span> <a name="line-84"></a><span class='hs-keyword'>import</span> <span class='hs-keyword'>qualified</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span><span class='hs-varop'>.</span><span class='hs-conid'>Trans</span><span class='hs-varop'>.</span><span class='hs-conid'>Writer</span><span class='hs-varop'>.</span><span class='hs-conid'>Strict</span> <span class='hs-keyword'>as</span> <span class='hs-conid'>W</span> <a name="line-85"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Monoid</span> <span class='hs-layout'>(</span><span class='hs-conid'>Monoid</span><span class='hs-layout'>,</span> <span class='hs-varid'>mappend</span><span class='hs-layout'>)</span> <a name="line-86"></a> <a name="line-87"></a><span class='hs-comment'>-- For documentation</span> <a name="line-88"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Exception</span> <span class='hs-layout'>(</span><span class='hs-varid'>try</span><span class='hs-layout'>,</span> <span class='hs-conid'>IOException</span><span class='hs-layout'>)</span> <a name="line-89"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-varop'>=<<</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span> <span class='hs-layout'>(</span><span class='hs-varop'>>=></span><span class='hs-layout'>)</span><span class='hs-layout'>,</span> <span class='hs-layout'>(</span><span class='hs-varop'><=<</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span> <span class='hs-varid'>join</span><span class='hs-layout'>)</span> <a name="line-90"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Functor</span><span class='hs-varop'>.</span><span class='hs-conid'>Identity</span> <span class='hs-layout'>(</span><span class='hs-conid'>Identity</span><span class='hs-layout'>)</span> <a name="line-91"></a> <a name="line-92"></a><span class='hs-comment'>{-| A functor in the category of monads, using 'hoist' as the analog of 'fmap': <a name="line-93"></a> <a name="line-94"></a>> hoist (f . g) = hoist f . hoist g <a name="line-95"></a>> <a name="line-96"></a>> hoist id = id <a name="line-97"></a>-}</span> <a name="line-98"></a><span class='hs-keyword'>class</span> <span class='hs-conid'>MFunctor</span> <span class='hs-varid'>t</span> <span class='hs-keyword'>where</span> <a name="line-99"></a> <span class='hs-comment'>{-| Lift a monad morphism from @m@ to @n@ into a monad morphism from <a name="line-100"></a> @(t m)@ to @(t n)@ <a name="line-101"></a> -}</span> <a name="line-102"></a> <span class='hs-varid'>hoist</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-conid'>Monad</span> <span class='hs-varid'>m</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-layout'>(</span><span class='hs-keyword'>forall</span> <span class='hs-varid'>a</span> <span class='hs-varop'>.</span> <span class='hs-varid'>m</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>n</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-varid'>m</span> <span class='hs-varid'>b</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-varid'>n</span> <span class='hs-varid'>b</span> <a name="line-103"></a> <a name="line-104"></a><a name="instance%20MFunctor%20(E.ErrorT%20e)"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>MFunctor</span> <span class='hs-layout'>(</span><span class='hs-conid'>E</span><span class='hs-varop'>.</span><span class='hs-conid'>ErrorT</span> <span class='hs-varid'>e</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-105"></a> <span class='hs-varid'>hoist</span> <span class='hs-varid'>nat</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>E</span><span class='hs-varop'>.</span><span class='hs-conid'>ErrorT</span> <span class='hs-layout'>(</span><span class='hs-varid'>nat</span> <span class='hs-layout'>(</span><span class='hs-conid'>E</span><span class='hs-varop'>.</span><span class='hs-varid'>runErrorT</span> <span class='hs-varid'>m</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-106"></a> <a name="line-107"></a><a name="instance%20MFunctor%20I.IdentityT"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>MFunctor</span> <span class='hs-conid'>I</span><span class='hs-varop'>.</span><span class='hs-conid'>IdentityT</span> <span class='hs-keyword'>where</span> <a name="line-108"></a> <span class='hs-varid'>hoist</span> <span class='hs-varid'>nat</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>I</span><span class='hs-varop'>.</span><span class='hs-conid'>IdentityT</span> <span class='hs-layout'>(</span><span class='hs-varid'>nat</span> <span class='hs-layout'>(</span><span class='hs-conid'>I</span><span class='hs-varop'>.</span><span class='hs-varid'>runIdentityT</span> <span class='hs-varid'>m</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-109"></a> <a name="line-110"></a><a name="instance%20MFunctor%20M.MaybeT"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>MFunctor</span> <span class='hs-conid'>M</span><span class='hs-varop'>.</span><span class='hs-conid'>MaybeT</span> <span class='hs-keyword'>where</span> <a name="line-111"></a> <span class='hs-varid'>hoist</span> <span class='hs-varid'>nat</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>M</span><span class='hs-varop'>.</span><span class='hs-conid'>MaybeT</span> <span class='hs-layout'>(</span><span class='hs-varid'>nat</span> <span class='hs-layout'>(</span><span class='hs-conid'>M</span><span class='hs-varop'>.</span><span class='hs-varid'>runMaybeT</span> <span class='hs-varid'>m</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-112"></a> <a name="line-113"></a><a name="instance%20MFunctor%20(R.ReaderT%20r)"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>MFunctor</span> <span class='hs-layout'>(</span><span class='hs-conid'>R</span><span class='hs-varop'>.</span><span class='hs-conid'>ReaderT</span> <span class='hs-varid'>r</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-114"></a> <span class='hs-varid'>hoist</span> <span class='hs-varid'>nat</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>R</span><span class='hs-varop'>.</span><span class='hs-conid'>ReaderT</span> <span class='hs-layout'>(</span><span class='hs-keyglyph'>\</span><span class='hs-varid'>i</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>nat</span> <span class='hs-layout'>(</span><span class='hs-conid'>R</span><span class='hs-varop'>.</span><span class='hs-varid'>runReaderT</span> <span class='hs-varid'>m</span> <span class='hs-varid'>i</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-115"></a> <a name="line-116"></a><a name="instance%20MFunctor%20(RWS.RWST%20r%20w%20s)"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>MFunctor</span> <span class='hs-layout'>(</span><span class='hs-conid'>RWS</span><span class='hs-varop'>.</span><span class='hs-conid'>RWST</span> <span class='hs-varid'>r</span> <span class='hs-varid'>w</span> <span class='hs-varid'>s</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-117"></a> <span class='hs-varid'>hoist</span> <span class='hs-varid'>nat</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>RWS</span><span class='hs-varop'>.</span><span class='hs-conid'>RWST</span> <span class='hs-layout'>(</span><span class='hs-keyglyph'>\</span><span class='hs-varid'>r</span> <span class='hs-varid'>s</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>nat</span> <span class='hs-layout'>(</span><span class='hs-conid'>RWS</span><span class='hs-varop'>.</span><span class='hs-varid'>runRWST</span> <span class='hs-varid'>m</span> <span class='hs-varid'>r</span> <span class='hs-varid'>s</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-118"></a> <a name="line-119"></a><a name="instance%20MFunctor%20(RWS'.RWST%20r%20w%20s)"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>MFunctor</span> <span class='hs-layout'>(</span><span class='hs-conid'>RWS'</span><span class='hs-varop'>.</span><span class='hs-conid'>RWST</span> <span class='hs-varid'>r</span> <span class='hs-varid'>w</span> <span class='hs-varid'>s</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-120"></a> <span class='hs-varid'>hoist</span> <span class='hs-varid'>nat</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>RWS'</span><span class='hs-varop'>.</span><span class='hs-conid'>RWST</span> <span class='hs-layout'>(</span><span class='hs-keyglyph'>\</span><span class='hs-varid'>r</span> <span class='hs-varid'>s</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>nat</span> <span class='hs-layout'>(</span><span class='hs-conid'>RWS'</span><span class='hs-varop'>.</span><span class='hs-varid'>runRWST</span> <span class='hs-varid'>m</span> <span class='hs-varid'>r</span> <span class='hs-varid'>s</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-121"></a> <a name="line-122"></a><a name="instance%20MFunctor%20(S.StateT%20s)"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>MFunctor</span> <span class='hs-layout'>(</span><span class='hs-conid'>S</span><span class='hs-varop'>.</span><span class='hs-conid'>StateT</span> <span class='hs-varid'>s</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-123"></a> <span class='hs-varid'>hoist</span> <span class='hs-varid'>nat</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>S</span><span class='hs-varop'>.</span><span class='hs-conid'>StateT</span> <span class='hs-layout'>(</span><span class='hs-keyglyph'>\</span><span class='hs-varid'>s</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>nat</span> <span class='hs-layout'>(</span><span class='hs-conid'>S</span><span class='hs-varop'>.</span><span class='hs-varid'>runStateT</span> <span class='hs-varid'>m</span> <span class='hs-varid'>s</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-124"></a> <a name="line-125"></a><a name="instance%20MFunctor%20(S'.StateT%20s)"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>MFunctor</span> <span class='hs-layout'>(</span><span class='hs-conid'>S'</span><span class='hs-varop'>.</span><span class='hs-conid'>StateT</span> <span class='hs-varid'>s</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-126"></a> <span class='hs-varid'>hoist</span> <span class='hs-varid'>nat</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>S'</span><span class='hs-varop'>.</span><span class='hs-conid'>StateT</span> <span class='hs-layout'>(</span><span class='hs-keyglyph'>\</span><span class='hs-varid'>s</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>nat</span> <span class='hs-layout'>(</span><span class='hs-conid'>S'</span><span class='hs-varop'>.</span><span class='hs-varid'>runStateT</span> <span class='hs-varid'>m</span> <span class='hs-varid'>s</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-127"></a> <a name="line-128"></a><a name="instance%20MFunctor%20(W.WriterT%20w)"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>MFunctor</span> <span class='hs-layout'>(</span><span class='hs-conid'>W</span><span class='hs-varop'>.</span><span class='hs-conid'>WriterT</span> <span class='hs-varid'>w</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-129"></a> <span class='hs-varid'>hoist</span> <span class='hs-varid'>nat</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>W</span><span class='hs-varop'>.</span><span class='hs-conid'>WriterT</span> <span class='hs-layout'>(</span><span class='hs-varid'>nat</span> <span class='hs-layout'>(</span><span class='hs-conid'>W</span><span class='hs-varop'>.</span><span class='hs-varid'>runWriterT</span> <span class='hs-varid'>m</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-130"></a> <a name="line-131"></a><a name="instance%20MFunctor%20(W'.WriterT%20w)"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>MFunctor</span> <span class='hs-layout'>(</span><span class='hs-conid'>W'</span><span class='hs-varop'>.</span><span class='hs-conid'>WriterT</span> <span class='hs-varid'>w</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-132"></a> <span class='hs-varid'>hoist</span> <span class='hs-varid'>nat</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>W'</span><span class='hs-varop'>.</span><span class='hs-conid'>WriterT</span> <span class='hs-layout'>(</span><span class='hs-varid'>nat</span> <span class='hs-layout'>(</span><span class='hs-conid'>W'</span><span class='hs-varop'>.</span><span class='hs-varid'>runWriterT</span> <span class='hs-varid'>m</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-133"></a> <a name="line-134"></a><a name="MMonad"></a><span class='hs-comment'>{-| A monad in the category of monads, using 'lift' from 'MonadTrans' as the <a name="line-135"></a> analog of 'return' and 'embed' as the analog of ('=<<'): <a name="line-136"></a> <a name="line-137"></a>> embed lift = id <a name="line-138"></a>> <a name="line-139"></a>> embed f (lift m) = f m <a name="line-140"></a>> <a name="line-141"></a>> embed g (embed f t) = embed (\m -> embed g (f m)) t <a name="line-142"></a>-}</span> <a name="line-143"></a><a name="MMonad"></a><span class='hs-keyword'>class</span> <span class='hs-layout'>(</span><span class='hs-conid'>MFunctor</span> <span class='hs-varid'>t</span><span class='hs-layout'>,</span> <span class='hs-conid'>MonadTrans</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-conid'>MMonad</span> <span class='hs-varid'>t</span> <span class='hs-keyword'>where</span> <a name="line-144"></a> <span class='hs-comment'>{-| Embed a newly created 'MMonad' layer within an existing layer <a name="line-145"></a> <a name="line-146"></a> 'embed' is analogous to ('=<<') <a name="line-147"></a> -}</span> <a name="line-148"></a> <span class='hs-varid'>embed</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-conid'>Monad</span> <span class='hs-varid'>n</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-layout'>(</span><span class='hs-keyword'>forall</span> <span class='hs-varid'>a</span> <span class='hs-varop'>.</span> <span class='hs-varid'>m</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-varid'>n</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-varid'>m</span> <span class='hs-varid'>b</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-varid'>n</span> <span class='hs-varid'>b</span> <a name="line-149"></a> <a name="line-150"></a><a name="squash"></a><span class='hs-comment'>{-| Squash two 'MMonad' layers into a single layer <a name="line-151"></a> <a name="line-152"></a> 'squash' is analogous to 'join' <a name="line-153"></a>-}</span> <a name="line-154"></a><span class='hs-definition'>squash</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-conid'>Monad</span> <span class='hs-varid'>m</span><span class='hs-layout'>,</span> <span class='hs-conid'>MMonad</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-varid'>t</span> <span class='hs-layout'>(</span><span class='hs-varid'>t</span> <span class='hs-varid'>m</span><span class='hs-layout'>)</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-varid'>m</span> <span class='hs-varid'>a</span> <a name="line-155"></a><span class='hs-definition'>squash</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>embed</span> <span class='hs-varid'>id</span> <a name="line-156"></a><span class='hs-comment'>{-# INLINABLE squash #-}</span> <a name="line-157"></a> <a name="line-158"></a><span class='hs-keyword'>infixr</span> <span class='hs-num'>2</span> <span class='hs-varop'>>|></span><span class='hs-layout'>,</span> <span class='hs-varop'>=<|</span> <a name="line-159"></a><span class='hs-keyword'>infixl</span> <span class='hs-num'>2</span> <span class='hs-varop'><|<</span><span class='hs-layout'>,</span> <span class='hs-varop'>|>=</span> <a name="line-160"></a> <a name="line-161"></a><a name="%3e%7c%3e"></a><span class='hs-comment'>{-| Compose two 'MMonad' layer-building functions <a name="line-162"></a> <a name="line-163"></a> ('>|>') is analogous to ('>=>') <a name="line-164"></a>-}</span> <a name="line-165"></a><span class='hs-layout'>(</span><span class='hs-varop'>>|></span><span class='hs-layout'>)</span> <a name="line-166"></a> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-conid'>Monad</span> <span class='hs-varid'>m3</span><span class='hs-layout'>,</span> <span class='hs-conid'>MMonad</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <a name="line-167"></a> <span class='hs-keyglyph'>=></span> <span class='hs-layout'>(</span><span class='hs-keyword'>forall</span> <span class='hs-varid'>a</span> <span class='hs-varop'>.</span> <span class='hs-varid'>m1</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-varid'>m2</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <a name="line-168"></a> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-keyword'>forall</span> <span class='hs-varid'>b</span> <span class='hs-varop'>.</span> <span class='hs-varid'>m2</span> <span class='hs-varid'>b</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-varid'>m3</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <a name="line-169"></a> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>m1</span> <span class='hs-varid'>c</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-varid'>m3</span> <span class='hs-varid'>c</span> <a name="line-170"></a><span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-varop'>>|></span> <span class='hs-varid'>g</span><span class='hs-layout'>)</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>embed</span> <span class='hs-varid'>g</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-varid'>m</span><span class='hs-layout'>)</span> <a name="line-171"></a><span class='hs-comment'>{-# INLINABLE (>|>) #-}</span> <a name="line-172"></a> <a name="line-173"></a><a name="%3c%7c%3c"></a><span class='hs-comment'>{-| Equivalent to ('>|>') with the arguments flipped <a name="line-174"></a> <a name="line-175"></a> ('<|<') is analogous to ('<=<') <a name="line-176"></a>-}</span> <a name="line-177"></a><span class='hs-layout'>(</span><span class='hs-varop'><|<</span><span class='hs-layout'>)</span> <a name="line-178"></a> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-conid'>Monad</span> <span class='hs-varid'>m3</span><span class='hs-layout'>,</span> <span class='hs-conid'>MMonad</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <a name="line-179"></a> <span class='hs-keyglyph'>=></span> <span class='hs-layout'>(</span><span class='hs-keyword'>forall</span> <span class='hs-varid'>b</span> <span class='hs-varop'>.</span> <span class='hs-varid'>m2</span> <span class='hs-varid'>b</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-varid'>m3</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <a name="line-180"></a> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-keyword'>forall</span> <span class='hs-varid'>a</span> <span class='hs-varop'>.</span> <span class='hs-varid'>m1</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-varid'>m2</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <a name="line-181"></a> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>m1</span> <span class='hs-varid'>c</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-varid'>m3</span> <span class='hs-varid'>c</span> <a name="line-182"></a><span class='hs-layout'>(</span><span class='hs-varid'>g</span> <span class='hs-varop'><|<</span> <span class='hs-varid'>f</span><span class='hs-layout'>)</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>embed</span> <span class='hs-varid'>g</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-varid'>m</span><span class='hs-layout'>)</span> <a name="line-183"></a><span class='hs-comment'>{-# INLINABLE (<|<) #-}</span> <a name="line-184"></a> <a name="line-185"></a><a name="=%3c%7c"></a><span class='hs-comment'>{-| An infix operator equivalent to 'embed' <a name="line-186"></a> <a name="line-187"></a> ('=<|') is analogous to ('=<<') <a name="line-188"></a>-}</span> <a name="line-189"></a><span class='hs-layout'>(</span><span class='hs-varop'>=<|</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-conid'>Monad</span> <span class='hs-varid'>n</span><span class='hs-layout'>,</span> <span class='hs-conid'>MMonad</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-layout'>(</span><span class='hs-keyword'>forall</span> <span class='hs-varid'>a</span> <span class='hs-varop'>.</span> <span class='hs-varid'>m</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-varid'>n</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-varid'>m</span> <span class='hs-varid'>b</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-varid'>n</span> <span class='hs-varid'>b</span> <a name="line-190"></a><span class='hs-layout'>(</span><span class='hs-varop'>=<|</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>embed</span> <a name="line-191"></a><span class='hs-comment'>{-# INLINABLE (=<|) #-}</span> <a name="line-192"></a> <a name="line-193"></a><a name="%7c%3e="></a><span class='hs-comment'>{-| Equivalent to ('=<|') with the arguments flipped <a name="line-194"></a> <a name="line-195"></a> ('|>=') is analogous to ('>>=') <a name="line-196"></a>-}</span> <a name="line-197"></a><span class='hs-layout'>(</span><span class='hs-varop'>|>=</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-conid'>Monad</span> <span class='hs-varid'>n</span><span class='hs-layout'>,</span> <span class='hs-conid'>MMonad</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-varid'>t</span> <span class='hs-varid'>m</span> <span class='hs-varid'>b</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-keyword'>forall</span> <span class='hs-varid'>a</span> <span class='hs-varop'>.</span> <span class='hs-varid'>m</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-varid'>n</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-varid'>n</span> <span class='hs-varid'>b</span> <a name="line-198"></a><a name="t"></a><span class='hs-definition'>t</span> <span class='hs-varop'>|>=</span> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>embed</span> <span class='hs-varid'>f</span> <span class='hs-varid'>t</span> <a name="line-199"></a><span class='hs-comment'>{-# INLINABLE (|>=) #-}</span> <a name="line-200"></a> <a name="line-201"></a><a name="instance%20MMonad%20(E.ErrorT%20e)"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span><span class='hs-conid'>E</span><span class='hs-varop'>.</span><span class='hs-conid'>Error</span> <span class='hs-varid'>e</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-conid'>MMonad</span> <span class='hs-layout'>(</span><span class='hs-conid'>E</span><span class='hs-varop'>.</span><span class='hs-conid'>ErrorT</span> <span class='hs-varid'>e</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-202"></a> <span class='hs-varid'>embed</span> <span class='hs-varid'>f</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>E</span><span class='hs-varop'>.</span><span class='hs-conid'>ErrorT</span> <span class='hs-layout'>(</span><span class='hs-keyword'>do</span> <a name="line-203"></a> <span class='hs-varid'>x</span> <span class='hs-keyglyph'><-</span> <span class='hs-conid'>E</span><span class='hs-varop'>.</span><span class='hs-varid'>runErrorT</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-layout'>(</span><span class='hs-conid'>E</span><span class='hs-varop'>.</span><span class='hs-varid'>runErrorT</span> <span class='hs-varid'>m</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-204"></a> <span class='hs-varid'>return</span> <span class='hs-layout'>(</span><span class='hs-keyword'>case</span> <span class='hs-varid'>x</span> <span class='hs-keyword'>of</span> <a name="line-205"></a> <span class='hs-conid'>Left</span> <span class='hs-varid'>e</span> <span class='hs-keyglyph'>-></span> <span class='hs-conid'>Left</span> <span class='hs-varid'>e</span> <a name="line-206"></a> <span class='hs-conid'>Right</span> <span class='hs-layout'>(</span><span class='hs-conid'>Left</span> <span class='hs-varid'>e</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-conid'>Left</span> <span class='hs-varid'>e</span> <a name="line-207"></a> <span class='hs-conid'>Right</span> <span class='hs-layout'>(</span><span class='hs-conid'>Right</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-conid'>Right</span> <span class='hs-varid'>a</span> <span class='hs-layout'>)</span> <span class='hs-layout'>)</span> <a name="line-208"></a> <a name="line-209"></a><a name="instance%20MMonad%20I.IdentityT"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>MMonad</span> <span class='hs-conid'>I</span><span class='hs-varop'>.</span><span class='hs-conid'>IdentityT</span> <span class='hs-keyword'>where</span> <a name="line-210"></a> <span class='hs-varid'>embed</span> <span class='hs-varid'>f</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>f</span> <span class='hs-layout'>(</span><span class='hs-conid'>I</span><span class='hs-varop'>.</span><span class='hs-varid'>runIdentityT</span> <span class='hs-varid'>m</span><span class='hs-layout'>)</span> <a name="line-211"></a> <a name="line-212"></a><a name="instance%20MMonad%20M.MaybeT"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>MMonad</span> <span class='hs-conid'>M</span><span class='hs-varop'>.</span><span class='hs-conid'>MaybeT</span> <span class='hs-keyword'>where</span> <a name="line-213"></a> <span class='hs-varid'>embed</span> <span class='hs-varid'>f</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>M</span><span class='hs-varop'>.</span><span class='hs-conid'>MaybeT</span> <span class='hs-layout'>(</span><span class='hs-keyword'>do</span> <a name="line-214"></a> <span class='hs-varid'>x</span> <span class='hs-keyglyph'><-</span> <span class='hs-conid'>M</span><span class='hs-varop'>.</span><span class='hs-varid'>runMaybeT</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-layout'>(</span><span class='hs-conid'>M</span><span class='hs-varop'>.</span><span class='hs-varid'>runMaybeT</span> <span class='hs-varid'>m</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-215"></a> <span class='hs-varid'>return</span> <span class='hs-layout'>(</span><span class='hs-keyword'>case</span> <span class='hs-varid'>x</span> <span class='hs-keyword'>of</span> <a name="line-216"></a> <span class='hs-conid'>Nothing</span> <span class='hs-keyglyph'>-></span> <span class='hs-conid'>Nothing</span> <a name="line-217"></a> <span class='hs-conid'>Just</span> <span class='hs-conid'>Nothing</span> <span class='hs-keyglyph'>-></span> <span class='hs-conid'>Nothing</span> <a name="line-218"></a> <span class='hs-conid'>Just</span> <span class='hs-layout'>(</span><span class='hs-conid'>Just</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-conid'>Just</span> <span class='hs-varid'>a</span> <span class='hs-layout'>)</span> <span class='hs-layout'>)</span> <a name="line-219"></a> <a name="line-220"></a><a name="instance%20MMonad%20(R.ReaderT%20r)"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>MMonad</span> <span class='hs-layout'>(</span><span class='hs-conid'>R</span><span class='hs-varop'>.</span><span class='hs-conid'>ReaderT</span> <span class='hs-varid'>r</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-221"></a> <span class='hs-varid'>embed</span> <span class='hs-varid'>f</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>R</span><span class='hs-varop'>.</span><span class='hs-conid'>ReaderT</span> <span class='hs-layout'>(</span><span class='hs-keyglyph'>\</span><span class='hs-varid'>i</span> <span class='hs-keyglyph'>-></span> <span class='hs-conid'>R</span><span class='hs-varop'>.</span><span class='hs-varid'>runReaderT</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-layout'>(</span><span class='hs-conid'>R</span><span class='hs-varop'>.</span><span class='hs-varid'>runReaderT</span> <span class='hs-varid'>m</span> <span class='hs-varid'>i</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <span class='hs-varid'>i</span><span class='hs-layout'>)</span> <a name="line-222"></a> <a name="line-223"></a><a name="instance%20MMonad%20(W.WriterT%20w)"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span><span class='hs-conid'>Monoid</span> <span class='hs-varid'>w</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-conid'>MMonad</span> <span class='hs-layout'>(</span><span class='hs-conid'>W</span><span class='hs-varop'>.</span><span class='hs-conid'>WriterT</span> <span class='hs-varid'>w</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-224"></a> <span class='hs-varid'>embed</span> <span class='hs-varid'>f</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>W</span><span class='hs-varop'>.</span><span class='hs-conid'>WriterT</span> <span class='hs-layout'>(</span><span class='hs-keyword'>do</span> <a name="line-225"></a> <span class='hs-keyglyph'>~</span><span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-varid'>w1</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span> <span class='hs-varid'>w2</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'><-</span> <span class='hs-conid'>W</span><span class='hs-varop'>.</span><span class='hs-varid'>runWriterT</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-layout'>(</span><span class='hs-conid'>W</span><span class='hs-varop'>.</span><span class='hs-varid'>runWriterT</span> <span class='hs-varid'>m</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-226"></a> <span class='hs-varid'>return</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-varid'>mappend</span> <span class='hs-varid'>w1</span> <span class='hs-varid'>w2</span><span class='hs-layout'>)</span> <span class='hs-layout'>)</span> <a name="line-227"></a> <a name="line-228"></a><a name="instance%20MMonad%20(W'.WriterT%20w)"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span><span class='hs-conid'>Monoid</span> <span class='hs-varid'>w</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-conid'>MMonad</span> <span class='hs-layout'>(</span><span class='hs-conid'>W'</span><span class='hs-varop'>.</span><span class='hs-conid'>WriterT</span> <span class='hs-varid'>w</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-229"></a> <span class='hs-varid'>embed</span> <span class='hs-varid'>f</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>W'</span><span class='hs-varop'>.</span><span class='hs-conid'>WriterT</span> <span class='hs-layout'>(</span><span class='hs-keyword'>do</span> <a name="line-230"></a> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-varid'>w1</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span> <span class='hs-varid'>w2</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'><-</span> <span class='hs-conid'>W'</span><span class='hs-varop'>.</span><span class='hs-varid'>runWriterT</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-layout'>(</span><span class='hs-conid'>W'</span><span class='hs-varop'>.</span><span class='hs-varid'>runWriterT</span> <span class='hs-varid'>m</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-231"></a> <span class='hs-varid'>return</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-varid'>mappend</span> <span class='hs-varid'>w1</span> <span class='hs-varid'>w2</span><span class='hs-layout'>)</span> <span class='hs-layout'>)</span> <a name="line-232"></a> <a name="line-233"></a><span class='hs-comment'>{- $tutorial <a name="line-234"></a> Monad morphisms solve the common problem of fixing monadic code after the <a name="line-235"></a> fact without modifying the original source code or type signatures. The <a name="line-236"></a> following sections illustrate various examples of transparently modifying <a name="line-237"></a> existing functions. <a name="line-238"></a>-}</span> <a name="line-239"></a> <a name="line-240"></a><span class='hs-comment'>{- $generalize <a name="line-241"></a> Imagine that some library provided the following 'S.State' code: <a name="line-242"></a> <a name="line-243"></a>> import Control.Monad.Trans.State <a name="line-244"></a>> <a name="line-245"></a>> tick :: State Int () <a name="line-246"></a>> tick = modify (+1) <a name="line-247"></a> <a name="line-248"></a> ... but we would prefer to reuse @tick@ within a larger <a name="line-249"></a> @('S.StateT' Int 'IO')@ block in order to mix in 'IO' actions. <a name="line-250"></a> <a name="line-251"></a> We could patch the original library to generalize @tick@'s type signature: <a name="line-252"></a> <a name="line-253"></a>> tick :: (Monad m) => StateT Int m () <a name="line-254"></a> <a name="line-255"></a> ... but we would prefer not to fork upstream code if possible. How could <a name="line-256"></a> we generalize @tick@'s type without modifying the original code? <a name="line-257"></a> <a name="line-258"></a> We can solve this if we realize that 'S.State' is a type synonym for <a name="line-259"></a> 'S.StateT' with an 'Identity' base monad: <a name="line-260"></a> <a name="line-261"></a>> type State s = StateT s Identity <a name="line-262"></a> <a name="line-263"></a> ... which means that @tick@'s true type is actually: <a name="line-264"></a> <a name="line-265"></a>> tick :: StateT Int Identity () <a name="line-266"></a> <a name="line-267"></a> Now all we need is a function that @generalize@s the 'Identity' base monad <a name="line-268"></a> to be any monad: <a name="line-269"></a> <a name="line-270"></a>> import Data.Functor.Identity <a name="line-271"></a>> <a name="line-272"></a>> generalize :: (Monad m) => Identity a -> m a <a name="line-273"></a>> generalize m = return (runIdentity m) <a name="line-274"></a> <a name="line-275"></a> ... which we can 'hoist' to change @tick@'s base monad: <a name="line-276"></a> <a name="line-277"></a>> hoist :: (Monad m, MFunctor t) => (forall a . m a -> n a) -> t m b -> t n b <a name="line-278"></a>> <a name="line-279"></a>> hoist generalize :: (Monad m, MFunctor t) => t Identity b -> t m b <a name="line-280"></a>> <a name="line-281"></a>> hoist generalize tick :: (Monad m) => StateT Int m () <a name="line-282"></a> <a name="line-283"></a> This lets us mix @tick@ alongside 'IO' using 'lift': <a name="line-284"></a> <a name="line-285"></a>> import Control.Monad.Morph <a name="line-286"></a>> import Control.Monad.Trans.Class <a name="line-287"></a>> <a name="line-288"></a>> tock :: StateT Int IO () <a name="line-289"></a>> tock = do <a name="line-290"></a>> hoist generalize tick :: (Monad m) => StateT Int m () <a name="line-291"></a>> lift $ putStrLn "Tock!" :: (MonadTrans t) => t IO () <a name="line-292"></a> <a name="line-293"></a>>>> runStateT tock 0 <a name="line-294"></a>Tock! <a name="line-295"></a>((), 1) <a name="line-296"></a> <a name="line-297"></a>-}</span> <a name="line-298"></a> <a name="line-299"></a><span class='hs-comment'>{- $mmorph <a name="line-300"></a> Notice that @generalize@ is a monad morphism, and the following two proofs <a name="line-301"></a> show how @generalize@ satisfies the monad morphism laws. You can refer to <a name="line-302"></a> these proofs as an example for how to prove a function obeys the monad <a name="line-303"></a> morphism laws: <a name="line-304"></a> <a name="line-305"></a>> generalize (return x) <a name="line-306"></a>> <a name="line-307"></a>> -- Definition of 'return' for the Identity monad <a name="line-308"></a>> = generalize (Identity x) <a name="line-309"></a>> <a name="line-310"></a>> -- Definition of 'generalize' <a name="line-311"></a>> = return (runIdentity (Identity x)) <a name="line-312"></a>> <a name="line-313"></a>> -- runIdentity (Identity x) = x <a name="line-314"></a>> = return x <a name="line-315"></a> <a name="line-316"></a>> generalize $ do x <- m <a name="line-317"></a>> f x <a name="line-318"></a>> <a name="line-319"></a>> -- Definition of (>>=) for the Identity monad <a name="line-320"></a>> = generalize (f (runIdentity m)) <a name="line-321"></a>> <a name="line-322"></a>> -- Definition of 'generalize' <a name="line-323"></a>> = return (runIdentity (f (runIdentity m))) <a name="line-324"></a>> <a name="line-325"></a>> -- Monad law: Left identity <a name="line-326"></a>> = do x <- return (runIdentity m) <a name="line-327"></a>> return (runIdentity (f x)) <a name="line-328"></a>> <a name="line-329"></a>> -- Definition of 'generalize' in reverse <a name="line-330"></a>> = do x <- generalize m <a name="line-331"></a>> generalize (f x) <a name="line-332"></a>-}</span> <a name="line-333"></a> <a name="line-334"></a><span class='hs-comment'>{- $interleave <a name="line-335"></a> You can combine 'hoist' and 'lift' to insert arbitrary layers anywhere <a name="line-336"></a> within a monad transformer stack. This comes in handy when interleaving two <a name="line-337"></a> diverse stacks. <a name="line-338"></a> <a name="line-339"></a> For example, we might want to combine the following @save@ function: <a name="line-340"></a> <a name="line-341"></a>> import Control.Monad.Trans.Writer <a name="line-342"></a>> <a name="line-343"></a>> -- i.e. :: StateT Int (WriterT [Int] Identity) () <a name="line-344"></a>> save :: StateT Int (Writer [Int]) () <a name="line-345"></a>> save = do <a name="line-346"></a>> n <- get <a name="line-347"></a>> lift $ tell [n] <a name="line-348"></a> <a name="line-349"></a> ... with our previous @tock@ function: <a name="line-350"></a> <a name="line-351"></a>> tock :: StateT Int IO () <a name="line-352"></a> <a name="line-353"></a> However, @save@ and @tock@ differ in two ways: <a name="line-354"></a> <a name="line-355"></a> * @tock@ lacks a 'W.WriterT' layer <a name="line-356"></a> <a name="line-357"></a> * @save@ has an 'Identity' base monad <a name="line-358"></a> <a name="line-359"></a> We can mix the two by inserting a 'W.WriterT' layer for @tock@ and <a name="line-360"></a> generalizing @save@'s base monad: <a name="line-361"></a> <a name="line-362"></a>> import Control.Monad <a name="line-363"></a>> <a name="line-364"></a>> program :: StateT Int (WriterT [Int] IO) () <a name="line-365"></a>> program = replicateM_ 4 $ do <a name="line-366"></a>> hoist lift tock <a name="line-367"></a>> :: (MonadTrans t) => StateT Int (t IO) () <a name="line-368"></a>> hoist (hoist generalize) save <a name="line-369"></a>> :: (Monad m) => StateT Int (WriterT [Int] m ) () <a name="line-370"></a> <a name="line-371"></a>>>> execWriterT (runStateT program 0) <a name="line-372"></a>Tock! <a name="line-373"></a>Tock! <a name="line-374"></a>Tock! <a name="line-375"></a>Tock! <a name="line-376"></a>[1,2,3,4] <a name="line-377"></a> <a name="line-378"></a>-}</span> <a name="line-379"></a> <a name="line-380"></a><span class='hs-comment'>{- $embed <a name="line-381"></a> Suppose we decided to @check@ all 'IOException's using a combination of <a name="line-382"></a> 'try' and 'ErrorT': <a name="line-383"></a> <a name="line-384"></a>> import Control.Exception <a name="line-385"></a>> import Control.Monad.Trans.Class <a name="line-386"></a>> import Control.Monad.Trans.Error <a name="line-387"></a>> <a name="line-388"></a>> check :: IO a -> ErrorT IOException IO a <a name="line-389"></a>> check io = ErrorT (try io) <a name="line-390"></a> <a name="line-391"></a> ... but then we forget to use @check@ in one spot, mistakenly using 'lift' <a name="line-392"></a> instead: <a name="line-393"></a> <a name="line-394"></a>> program :: ErrorT IOException IO () <a name="line-395"></a>> program = do <a name="line-396"></a>> str <- lift $ readFile "test.txt" <a name="line-397"></a>> check $ putStr str <a name="line-398"></a> <a name="line-399"></a>>>> runErrorT program <a name="line-400"></a>*** Exception: test.txt: openFile: does not exist (No such file or directory) <a name="line-401"></a> <a name="line-402"></a> How could we go back and fix 'program' without modifying its source code? <a name="line-403"></a> <a name="line-404"></a> Well, @check@ is a monad morphism, but we can't 'hoist' it to modify the <a name="line-405"></a> base monad because then we get two 'E.ErrorT' layers instead of one: <a name="line-406"></a> <a name="line-407"></a>> hoist check :: (MFunctor t) => t IO a -> t (ErrorT IOException IO) a <a name="line-408"></a>> <a name="line-409"></a>> hoist check program :: ErrorT IOException (ErrorT IOException IO) () <a name="line-410"></a> <a name="line-411"></a> We'd prefer to 'embed' all newly generated exceptions in the existing <a name="line-412"></a> 'E.ErrorT' layer: <a name="line-413"></a> <a name="line-414"></a>> embed check :: ErrorT IOException IO a -> ErrorT IOException IO a <a name="line-415"></a>> <a name="line-416"></a>> embed check program :: ErrorT IOException IO () <a name="line-417"></a> <a name="line-418"></a> This correctly checks the exceptions that slipped through the cracks: <a name="line-419"></a> <a name="line-420"></a>>>> import Control.Monad.Morph <a name="line-421"></a>>>> runErrorT (embed check program) <a name="line-422"></a>Left test.txt: openFile: does not exist (No such file or directory) <a name="line-423"></a> <a name="line-424"></a>-}</span> </pre></body> </html>