Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>If you are willing to slightly modify the original interpreter (by changing how the terminal case is handled)</p> <pre><code>{-# LANGUAGE DeriveFunctor #-} import Control.Monad.Free import Control.Monad.Morph import Pipes data FooF a = Foo String a | Bar Int a deriving (Functor) printFoo :: Free FooF a -&gt; IO a printFoo (Free (Foo s n)) = print s &gt;&gt; printFoo n printFoo (Free (Bar i n)) = print i &gt;&gt; printFoo n printFoo (Pure a) = return a </code></pre> <p>...then there's a way to add extra actions without modifying the functor or having to repurpose its constructors, while still being able to reuse the interpreter.</p> <p>The solution uses the <code>pipes</code> and <code>mmorph</code> packages.</p> <p>First you have to define a sort of "pre-interpeter" that lifts the free monad into a <code>Producer</code> from <code>pipes</code>. The <code>yield ()</code> statements in the producer signify the points at which an extra action is inserted.</p> <pre><code>pre :: Free FooF a -&gt; Producer () (Free FooF) a pre (Free (Foo s n)) = lift (Free . Foo s $ return ()) &gt;&gt; yield () &gt;&gt; pre n pre (Free (Bar i n)) = lift (Free . Bar i $ return ()) &gt;&gt; yield () &gt;&gt; pre n pre (Pure a) = lift . Pure $ a </code></pre> <p>(In a more complex example the <code>yield</code> statements could carry extra information, like log messages.)</p> <p>Then you write a function that applies the <code>printFoo</code> interpreter <em>underneath</em> the <code>Producer</code>, using <code>hoist</code> from <code>mmorph</code>:</p> <pre><code>printFooUnder :: Producer () (Free FooF) a -&gt; Producer () IO a printFooUnder = hoist printFoo </code></pre> <p>So, we have a function that "interprets" the free monad into <code>IO</code>, but at some points emits <code>()</code> values that we must decide how to handle.</p> <p>Now we can define an extended interpreter that reuses the old interpreter:</p> <pre><code>printFooWithReuse :: Show a =&gt; Free FooF a -&gt; IO () printFooWithReuse foo = do finalv &lt;- runEffect $ for (printFooUnder . pre $ foo) (\_ -&gt; lift (print "extra info")) print finalv </code></pre> <p>After testing it, it seems to work:</p> <pre><code>printFooWithReuse $ Free (Foo "nah" (Pure 4)) -- &gt; "nah" -- &gt; "extra info" -- &gt; 4 </code></pre> <p>If you happen to want to insert the extra actions manually, then your can eschew writing the "pre-interpreter" and work directly in the <code>Producer () (Free FooF)</code> monad.</p> <p>(This solution could also be achieved by layering a free monad transformer instead of a <code>Producer</code>. But I think using a <code>Producer</code> is a bit easier.)</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload