Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>If we compare the types</p> <pre><code>(&lt;*&gt;) :: Applicative a =&gt; a (s -&gt; t) -&gt; a s -&gt; a t (&gt;&gt;=) :: Monad m =&gt; m s -&gt; (s -&gt; m t) -&gt; m t </code></pre> <p>we get a clue to what separates the two concepts. That <code>(s -&gt; m t)</code> in the type of <code>(&gt;&gt;=)</code> shows that a value in <code>s</code> can determine the behaviour of a computation in <code>m t</code>. Monads allow interference between the value and computation layers. The <code>(&lt;*&gt;)</code> operator allows no such interference: the function and argument computations don't depend on values. This really bites. Compare</p> <pre><code>miffy :: Monad m =&gt; m Bool -&gt; m x -&gt; m x -&gt; m x miffy mb mt mf = do b &lt;- mb if b then mt else mf </code></pre> <p>which uses the result of some effect to decide between two <em>computations</em> (e.g. launching missiles and signing an armistice), whereas</p> <pre><code>iffy :: Applicative a =&gt; a Bool -&gt; a x -&gt; a x -&gt; a x iffy ab at af = pure cond &lt;*&gt; ab &lt;*&gt; at &lt;*&gt; af where cond b t f = if b then t else f </code></pre> <p>which uses the value of <code>ab</code> to choose between <em>the values of</em> two computations <code>at</code> and <code>af</code>, having carried out both, perhaps to tragic effect.</p> <p>The monadic version relies essentially on the extra power of <code>(&gt;&gt;=)</code> to choose a computation from a value, and that can be important. However, supporting that power makes monads hard to compose. If we try to build &lsquo;double-bind&rsquo;</p> <pre><code>(&gt;&gt;&gt;&gt;==) :: (Monad m, Monad n) =&gt; m (n s) -&gt; (s -&gt; m (n t)) -&gt; m (n t) mns &gt;&gt;&gt;&gt;== f = mns &gt;&gt;-{-m-} \ ns -&gt; let nmnt = ns &gt;&gt;= (return . f) in ??? </code></pre> <p>we get this far, but now our layers are all jumbled up. We have an <code>n (m (n t))</code>, so we need to get rid of the outer <code>n</code>. As Alexandre C says, we can do that if we have a suitable</p> <pre><code>swap :: n (m t) -&gt; m (n t) </code></pre> <p>to permute the <code>n</code> inwards and <code>join</code> it to the other <code>n</code>.</p> <p>The weaker &lsquo;double-apply&rsquo; is much easier to define</p> <pre><code>(&lt;&lt;**&gt;&gt;) :: (Applicative a, Applicative b) =&gt; a (b (s -&gt; t)) -&gt; a (b s) -&gt; a (b t) abf &lt;&lt;**&gt;&gt; abs = pure (&lt;*&gt;) &lt;*&gt; abf &lt;*&gt; abs </code></pre> <p>because there is no interference between the layers.</p> <p>Correspondingly, it's good to recognize when you really need the extra power of <code>Monad</code>s, and when you can get away with the rigid computation structure that <code>Applicative</code> supports.</p> <p>Note, by the way, that although composing monads is difficult, it might be more than you need. The type <code>m (n v)</code> indicates computing with <code>m</code>-effects, then computing with <code>n</code>-effects to a <code>v</code>-value, where the <code>m</code>-effects finish before the <code>n</code>-effects start (hence the need for <code>swap</code>). If you just want to interleave <code>m</code>-effects with <code>n</code>-effects, then composition is perhaps too much to ask!</p>
 

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