Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Here's a couple of functions that use the <code>Monad</code> interface.</p> <pre><code>ifM :: Monad m =&gt; m Bool -&gt; m a -&gt; m a -&gt; m a ifM c x y = c &gt;&gt;= \z -&gt; if z then x else y whileM :: Monad m =&gt; (a -&gt; m Bool) -&gt; (a -&gt; m a) -&gt; a -&gt; m a whileM p step x = ifM (p x) (step x &gt;&gt;= whileM p step) (return x) </code></pre> <p>You can't implement them with the <code>Applicative</code> interface. But for the sake of enlightenment, let's try and see where things go wrong. How about..</p> <pre><code>import Control.Applicative ifA :: Applicative f =&gt; f Bool -&gt; f a -&gt; f a -&gt; f a ifA c x y = (\c' x' y' -&gt; if c' then x' else y') &lt;$&gt; c &lt;*&gt; x &lt;*&gt; y </code></pre> <p>Looks good! It has the right type, it must be the same thing! Let's just check to make sure..</p> <pre><code>*Main&gt; ifM (Just True) (Just 1) (Just 2) Just 1 *Main&gt; ifM (Just True) (Just 1) (Nothing) Just 1 *Main&gt; ifA (Just True) (Just 1) (Just 2) Just 1 *Main&gt; ifA (Just True) (Just 1) (Nothing) Nothing </code></pre> <p>And there's your first hint at the difference. You can't write a function using just the <code>Applicative</code> interface that replicates <code>ifM</code>.</p> <p>If you divide this up into thinking about values of the form <code>f a</code> as being about "effects" and "results" (both of which are very fuzzy approximate terms that are the best terms available, but not very good), you can improve your understanding here. In the case of values of type <code>Maybe a</code>, the "effect" is success or failure, as a computation. The "result" is a value of type <code>a</code> that might be present when the computation completes. (The meanings of these terms depends heavily on the concrete type, so don't think this is a valid description of anything other than <code>Maybe</code> as a type.) </p> <p>Given that setting, we can look at the difference in a bit more depth. The <code>Applicative</code> interface allows the "result" control flow to be dynamic, but it requires the "effect" control flow to be static. If your expression involves 3 computations that can fail, the failure of any one of them causes the failure of the whole computation. The <code>Monad</code> interface is more flexible. It allows the "effect" control flow to depend on the "result" values. <code>ifM</code> chooses which argument's "effects" to include in its own "effects" based on its first argument. This is the huge fundamental difference between <code>ifA</code> and <code>ifM</code>.</p> <p>There's something even more serious going on with <code>whileM</code>. Let's try to make <code>whileA</code> and see what happens.</p> <pre><code>whileA :: Applicative f =&gt; (a -&gt; f Bool) -&gt; (a -&gt; f a) -&gt; a -&gt; f a whileA p step x = ifA (p x) (whileA p step &lt;*&gt; step x) (pure x) </code></pre> <p>Well.. What happens is a compile error. <code>(&lt;*&gt;)</code> doesn't have the right type there. <code>whileA p step</code> has the type <code>a -&gt; f a</code> and <code>step x</code> has the type <code>f a</code>. <code>(&lt;*&gt;)</code> isn't the right shape to fit them together. For it to work, the function type would need to be <code>f (a -&gt; a)</code>.</p> <p>You can try lots more things - but you'll eventually find that <code>whileA</code> has no implementation that works anything even close to the way <code>whileM</code> does. I mean, you can implement the type, but there's just no way to make it both loop and terminate.</p> <p>Making it work <em>requires</em> either <code>join</code> or <code>(&gt;&gt;=)</code>. (Well, or one of the many equivalents of one of those) And those the extra things you get out of the <code>Monad</code> interface.</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