Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Let's imagine we were to <code>IO</code>-ify the <code>State</code> monad. What would that look like? Our pure <code>State</code> monad is just a newtype around:</p> <pre><code>s -&gt; (a, s) </code></pre> <p>Well, the <code>IO</code> version might do a little bit of side effects before returning the final values, which would look like:</p> <pre><code>s -&gt; IO (a, s) </code></pre> <p>That pattern is so common it has a name, specifically <code>StateT</code>:</p> <pre><code>newtype StateT s m a = StateT { runStateT :: s -&gt; m (a, s) } </code></pre> <p>The name has a <code>T</code> at the end because it is a monad <code>T</code>ransformer. We call <code>m</code> the "base monad" and <code>StateT s m</code> the "transformed" monad.</p> <p><code>StateT s m</code> is only a <code>Monad</code> if <code>m</code> is a <code>Monad</code>:</p> <pre><code>instance (Monad m) =&gt; Monad (StateT s m) where {- great exercise -} </code></pre> <p>However, in addition to that, all monad transformers implement the <code>MonadTrans</code> class, defined as follows:</p> <pre><code>class MonadTrans t where lift :: (Monad m) =&gt; m a -&gt; t m a instance MonadTrans (StateT s) where {- great exercise -} </code></pre> <p>If <code>t</code> is <code>StateT s</code>, then <code>lift</code>'s type specializes to:</p> <pre><code>lift :: m a -&gt; StateT s m a </code></pre> <p>In other words, it lets us "lift" an action in the base monad to become an action in the transformed monad.</p> <p>So, for your specific problem, you want the <code>StateT (IntMap k v) IO</code> monad, which extends <code>IO</code> with additional <code>State</code>. Then you can write your entire program in this monad:</p> <pre><code>main = flip runStateT (initialState :: IntMap k v) $ do m &lt;- get -- retrieve the map lift $ print m -- lift an IO action (k, v) &lt;- lift readLn put (insert k v m) </code></pre> <p>Notice that I still use <code>get</code> and <code>put</code>. That's because the <code>transformers</code> package implements all the concepts I described and it generalizes the signatures of <code>get</code> and <code>put</code> to be:</p> <pre><code>get :: (Monad m) =&gt; StateT s m s put :: (Monad m) =&gt; s -&gt; StateT s m () </code></pre> <p>That means they automatically work within <code>StateT</code>. <code>transformers</code> then just defines <code>State</code> as:</p> <pre><code>type State s = StateT s Identity </code></pre> <p>That means that you can use <code>get</code> and <code>put</code> for both <code>State</code> and <code>StateT</code>.</p> <p>To learn more about monad transformers, I highly recommend <a href="http://www.cs.virginia.edu/~wh5a/personal/Transformers.pdf" rel="noreferrer">Monad Transformers - Step by Step</a>.</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. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      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