Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change Monad and Alternative definitions, on the website #52

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 32 additions & 47 deletions docs/a-fistful-of-monads.html
Original file line number Diff line number Diff line change
Expand Up @@ -381,29 +381,22 @@ <h2>The Monad type class</h2>
</p>

<pre name="code" class="haskell:hs">
class Monad m where
class Applicative m =&gt; Monad m where
return :: a -&gt; m a
return = pure

(&gt;&gt;=) :: m a -&gt; (a -&gt; m b) -&gt; m b

(&gt;&gt;) :: m a -&gt; m b -&gt; m b
x &gt;&gt; y = x &gt;&gt;= \_ -&gt; y

fail :: String -&gt; m a
fail msg = error msg
</pre>

<img src="assets/images/a-fistful-of-monads/kid.png" alt="this is you on monads" class="right" width="363" height="451">
<p>
Let's start with the first line. It says <span class="fixed">class Monad m where</span>.
But wait, didn't we say that monads are just beefed up applicative functors? Shouldn't
there be a class constraint in there along the lines of <span
class="fixed">class (Applicative m) = &gt; Monad m where</span> so that a type
has to be an applicative functor first before it can be made a monad? Well,
there should, but when Haskell was made, it hadn't occurred to people that
applicative functors are a good fit for Haskell so they weren't in there. But
rest assured, every monad is an applicative functor, even if the <span
class="fixed">Monad</span> class declaration doesn't say so.
Let's start with the first line. It says
<span class="fixed">class (Applicative m) = &gt; Monad m where</span> which means
that if we want to create an instance of Monad for some type, we must have an
instance of Applicative for that type.
</p>

<p>
Expand Down Expand Up @@ -445,11 +438,6 @@ <h2>The Monad type class</h2>
instances.
</p>

<p>
The final function of the <span class="fixed">Monad</span> type class is
<span class="fixed">fail</span>. We never use it explicitly in our code. Instead, it's used by Haskell to enable failure in a special syntactic construct for monads that we'll meet later. We don't need to concern ourselves with <span class="fixed">fail</span> too much for now.
</p>

<p>
Now that we know what the <span class="fixed">Monad</span> type class looks
like, let's take a look at how <span class="fixed">Maybe</span> is an instance
Expand All @@ -458,17 +446,15 @@ <h2>The Monad type class</h2>

<pre name="code" class="haskell:hs">
instance Monad Maybe where
return x = Just x
Nothing &gt;&gt;= f = Nothing
Just x &gt;&gt;= f = f x
fail _ = Nothing
</pre>

<p>
<span class="fixed">return</span> is the same as <span
class="fixed">pure</span>, so that one's a no-brainer. We do what we did in the
<span class="fixed">Applicative</span> type class and wrap it in a <span
class="fixed">Just</span>.
Both <span class="fixed">return</span> and <span class="fixed">(&gt;&gt;)</span> have <em>default
implementations</em>, so we omit them in instances. <span class="fixed">return</span>
is the same as <span class="fixed">pure</span>, it wraps a value in
<span class="fixed">Just</span>.
</p>

<p>
Expand Down Expand Up @@ -1274,25 +1260,26 @@ <h2>do notation</h2>
present in <span class="fixed">let</span> expressions. When pattern matching
fails in a <span class="fixed">do</span> expression, the <span
class="fixed">fail</span> function is called. It's part of the <span
class="fixed">Monad</span> type class and it enables failed pattern matching to
class="fixed">MonadFail</span> type class and it enables failed pattern matching to
result in a failure in the context of the current monad instead of making our
program crash. Its default implementation is this:
program crash.
</p>

<pre name="code" class="haskell:hs">
fail :: (Monad m) =&gt; String -&gt; m a
fail msg = error msg
class Monad m =&gt; MonadFail m where
fail :: String -&gt; m a
</pre>

<p>
So by default it does make our program crash, but monads that incorporate a
Monads that incorporate a
context of possible failure (like <span class="fixed">Maybe</span>) usually
implement it on their own. For <span class="fixed">Maybe</span>, its implemented
like so:
</p>

<pre name="code" class="haskell:hs">
fail _ = Nothing
instance MonadFail Maybe where
fail _ = Nothing
</pre>

<p>
Expand Down Expand Up @@ -1368,9 +1355,7 @@ <h2>The list monad</h2>

<pre name="code" class="haskell:hs">
instance Monad [] where
return x = [x]
xs &gt;&gt;= f = concat (map f xs)
fail _ = []
</pre>

<p>
Expand Down Expand Up @@ -1563,41 +1548,41 @@ <h2>The list monad</h2>
class="fixed">'7'</span> is part of that string. Pretty clever. To see how
filtering in list comprehensions translates to the list monad, we have to check
out the <span class="fixed">guard</span> function and the <span
class="fixed">MonadPlus</span> type class. The <span class="fixed">MonadPlus</span>
type class is for monads that can also act as monoids. Here's its definition:
class="fixed">Alternative</span> type class. The <span class="fixed">Alternative</span>
type class is for Applicatives that can also act as monoids. Here's its definition:
</p>

<pre name="code" class="haskell:hs">
class Monad m =&gt; MonadPlus m where
mzero :: m a
mplus :: m a -&gt; m a -&gt; m a
class Applicative f =&gt; Alternative f where
empty :: f a
(&lt;|&gt;) :: f a -&gt; f a -&gt; f a
</pre>

<p>
<span class="fixed">mzero</span> is synonymous to <span class="fixed">mempty</span>
<span class="fixed">empty</span> is synonymous to <span class="fixed">mempty</span>
from the <span class="fixed">Monoid</span> type class and <span
class="fixed">mplus</span> corresponds to <span class="fixed">mappend</span>.
class="fixed">(&lt;|&gt;)</span> corresponds to <span class="fixed">mappend</span>.
Because lists are monoids as well as monads, they can be made an instance of
this type class:
</p>

<pre name="code" class="haskell:hs">
instance MonadPlus [] where
mzero = []
mplus = (++)
instance Alternative [] where
empty = []
(&lt;&gt;) = (++)
</pre>

<p>
For lists <span class="fixed">mzero</span> represents a non-deterministic
For lists <span class="fixed">empty</span> represents a non-deterministic
computation that has no results at all &mdash; a failed computation. <span
class="fixed">mplus</span> joins two non-deterministic values into one. The
class="fixed">(&lt;|&gt;)</span> joins two non-deterministic values into one. The
<span class="fixed">guard</span> function is defined like this:
</p>

<pre name="code" class="haskell:hs">
guard :: (MonadPlus m) =&gt; Bool -&gt; m ()
guard True = return ()
guard False = mzero
guard :: (Alternative m) =&gt; Bool -&gt; m ()
guard True = pure ()
guard False = empty
</pre>

<p>
Expand Down