diff --git a/markdown/generated_html/a-fistful-of-monads.html b/markdown/generated_html/a-fistful-of-monads.html index 226f740..5c95877 100644 --- a/markdown/generated_html/a-fistful-of-monads.html +++ b/markdown/generated_html/a-fistful-of-monads.html @@ -254,29 +254,20 @@
Applicative
type class,
monads come with their own type class: Monad
! Wow, who
would have thought? This is what the type class looks like:
-class Monad m where
+class Applicative m => Monad m where
return :: a -> m a
+ return = pure
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
- x >> y = x >>= \_ -> y
-
- fail :: String -> m a
- fail msg = error msg
+ x >> y = x >>= \_ -> y
Let’s start with the first line. It says
-class Monad m where
. 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
-class (Applicative m) = > Monad m where
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 Monad
class declaration doesn’t say
-so.
class Applicative => Monad m where
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.
The first function that the Monad
type class defines is
return
. It’s the same as pure
, only with a
different name. Its type is (Monad m) => a -> m a
. It
@@ -305,22 +296,16 @@
Monad
instances.
-The final function of the Monad
type class is
-fail
. 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
-fail
too much for now.
Now that we know what the Monad
type class looks like,
let’s take a look at how Maybe
is an instance of
Monad
!
instance Monad Maybe where
- return x = Just x
Nothing >>= f = Nothing
- Just x >>= f = f x
- fail _ = Nothing
-return
is the same as pure
, so that one’s a
-no-brainer. We do what we did in the Applicative
type class
-and wrap it in a Just
.
Both return
and (>>)
have default
+implementations, so we omit them in instances. return
+is the same as pure
, it wraps a value in
+Just
.
The >>=
function is the same as our
applyMaybe
. When feeding the Maybe a
to our
function, we keep in mind the context and return a Nothing
@@ -811,17 +796,16 @@
let
expressions. When pattern matching
fails in a do
expression, the fail
function is
-called. It’s part of the Monad
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:
-fail :: (Monad m) => String -> m a
-fail msg = error msg
-So by default it does make our program crash, but monads that
-incorporate a context of possible failure (like Maybe
)
-usually implement it on their own. For Maybe
, its
+called. It’s part of the MonadFail
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.
class Monad m => MonadFail m where
+ fail :: String -> m a
+Monads that incorporate a context of possible failure (like
+Maybe
) usually implement it. For Maybe
, its
implemented like so:
fail _ = Nothing
+instance MonadFail Maybe where
+ fail _ = Nothing
It ignores the error message and makes a Nothing
. So
when pattern matching fails in a Maybe
value that’s written
in do
notation, the whole value results in a
@@ -867,9 +851,7 @@
Monad
instance for lists
looks like:
instance Monad [] where
- return x = [x]
- xs >>= f = concat (map f xs)
- fail _ = []
+ xs >>= f = concat (map f xs)
return
does the same thing as pure
, so we
should already be familiar with return
for lists. It takes
a value and puts it in a minimal default context that still yields that
@@ -986,26 +968,26 @@
'7'
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
-guard
function and the MonadPlus
type class.
-The MonadPlus
type class is for monads that can also act as
-monoids. Here’s its definition:
-class Monad m => MonadPlus m where
- mzero :: m a
- mplus :: m a -> m a -> m a
-mzero
is synonymous to mempty
from the
-Monoid
type class and mplus
corresponds to
-mappend
. Because lists are monoids as well as monads, they
-can be made an instance of this type class:
instance MonadPlus [] where
- mzero = []
- mplus = (++)
-For lists mzero
represents a non-deterministic
+guard
function and the Alternative
type class.
+The Alternative
type class is for Applicatives that can
+also act as monoids. Here’s its definition:
class Applicative f => Alternative f where
+ empty :: f a
+ (<|>) :: f a -> f a -> f a
+empty
is synonymous to mempty
from the
+Monoid
type class and (<|>)
corresponds
+to mappend
. Because lists are monoids as well as monads,
+they can be made an instance of this type class:
instance Alternative [] where
+ empty = []
+ (<|>) = (++)
+For lists empty
represents a non-deterministic
computation that has no results at all — a failed computation.
-mplus
joins two non-deterministic values into one. The
-guard
function is defined like this:
guard :: (MonadPlus m) => Bool -> m ()
-guard True = return ()
-guard False = mzero
+(<|>)
joins two non-deterministic values into one.
+The guard
function is defined like this:
+guard :: (Alternative m) => Bool -> m ()
+guard True = pure ()
+guard False = empty
It takes a boolean value and if it’s True
, takes a
()
and puts it in a minimal default context that still
succeeds. Otherwise, it makes a failed monadic value. Here it is in
diff --git a/markdown/source_md/a-fistful-of-monads.md b/markdown/source_md/a-fistful-of-monads.md
index 9eaf959..00c3d55 100644
--- a/markdown/source_md/a-fistful-of-monads.md
+++ b/markdown/source_md/a-fistful-of-monads.md
@@ -1,4 +1,4 @@
-# A Fistful of Monads
+# A Fistful of Monads
When we first talked about functors, we saw that they were a useful concept for values that can be mapped over.
Then, we took that concept one step further by introducing applicative functors, which allow us to view values of certain data types as values with contexts and use normal functions on those values while preserving the meaning of those contexts.
@@ -205,26 +205,20 @@ Wow, who would have thought?
This is what the type class looks like:
```{.haskell:hs}
-class Monad m where
+class Applicative m => Monad m where
return :: a -> m a
+ return = pure
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
x >> y = x >>= \_ -> y
-
- fail :: String -> m a
- fail msg = error msg
```
{.right width=363 height=451}
Let's start with the first line.
-It says `class Monad m where`.
-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 `class (Applicative m) = > Monad m where` 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 `Monad` class declaration doesn't say so.
+It says `class Applicative => Monad m where`, which means that if we want to create an instance of `Monad` for some type, we must also have an instance of `Applicative` for that type.
The first function that the `Monad` type class defines is `return`.
It's the same as `pure`, only with a different name.
@@ -249,23 +243,16 @@ It's like function application, only instead of taking a normal value and feedin
Next up, we have `>>`.
We won't pay too much attention to it for now because it comes with a default implementation and we pretty much never implement it when making `Monad` instances.
-The final function of the `Monad` type class is `fail`.
-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 `fail` too much for now.
-
Now that we know what the `Monad` type class looks like, let's take a look at how `Maybe` is an instance of `Monad`!
```{.haskell:hs}
instance Monad Maybe where
- return x = Just x
Nothing >>= f = Nothing
Just x >>= f = f x
- fail _ = Nothing
```
-`return` is the same as `pure`, so that one's a no-brainer.
-We do what we did in the `Applicative` type class and wrap it in a `Just`.
+Both `return` and `(>>)` have _default implementations_, so we can omit them in instances.
+`return` is the same as `pure`, it wraps a value in `Just`.
The `>>=` function is the same as our `applyMaybe`.
When feeding the `Maybe a` to our function, we keep in mind the context and return a `Nothing` if the value on the left is `Nothing` because if there's no value then there's no way to apply our function to it.
@@ -779,19 +766,19 @@ When matching on a pattern in a function fails, the next pattern is matched.
If the matching falls through all the patterns for a given function, an error is thrown and our program crashes.
On the other hand, failed pattern matching in `let` expressions results in an error being produced right away, because the mechanism of falling through patterns isn't present in `let` expressions.
When pattern matching fails in a `do` expression, the `fail` function is called.
-It's part of the `Monad` 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:
+It's part of the `MonadFail` 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.
```{.haskell:hs}
-fail :: (Monad m) => String -> m a
-fail msg = error msg
+class Monad m => MonadFail m where
+ fail :: String -> m a
```
-So by default it does make our program crash, but monads that incorporate a context of possible failure (like `Maybe`) usually implement it on their own.
+Monads that incorporate a context of possible failure (like `Maybe`) usually implement it.
For `Maybe`, its implemented like so:
```{.haskell:hs}
-fail _ = Nothing
+instance MonadFail Maybe where
+ fail _ = Nothing
```
It ignores the error message and makes a `Nothing`.
@@ -842,9 +829,7 @@ Let's go ahead and see what the `Monad` instance for lists looks like:
```{.haskell:hs}
instance Monad [] where
- return x = [x]
xs >>= f = concat (map f xs)
- fail _ = []
```
`return` does the same thing as `pure`, so we should already be familiar with `return` for lists.
@@ -962,33 +947,33 @@ ghci> [ x | x <- [1..50], '7' `elem` show x ]
We apply `show` to `x` to turn our number into a string and then we check if the character `'7'` 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 `guard` function and the `MonadPlus` type class.
-The `MonadPlus` type class is for monads that can also act as monoids.
+To see how filtering in list comprehensions translates to the list monad, we have to check out the `guard` function and the `Alternative` type class.
+The `Alternative` type class is for applicative functors that can also act as monoids.
Here's its definition:
```{.haskell:hs}
-class Monad m => MonadPlus m where
- mzero :: m a
- mplus :: m a -> m a -> m a
+class Applicative f => Alternative f where
+ empty :: f a
+ (<|>) :: f a -> f a -> f a
```
-`mzero` is synonymous to `mempty` from the `Monoid` type class and `mplus` corresponds to `mappend`.
+`empty` is synonymous to `mempty` from the `Monoid` type class and `(<|>)` corresponds to `mappend`.
Because lists are monoids as well as monads, they can be made an instance of this type class:
```{.haskell:hs}
-instance MonadPlus [] where
- mzero = []
- mplus = (++)
+instance Alternative [] where
+ empty = []
+ (<|>) = (++)
```
-For lists `mzero` represents a non-deterministic computation that has no results at all --- a failed computation.
-`mplus` joins two non-deterministic values into one.
+For lists, `empty` represents a non-deterministic computation that has no results at all --- a failed computation.
+`(<|>)` joins two non-deterministic values into one.
The `guard` function is defined like this:
```{.haskell:hs}
-guard :: (MonadPlus m) => Bool -> m ()
-guard True = return ()
-guard False = mzero
+guard :: (Alternative m) => Bool -> m ()
+guard True = pure ()
+guard False = empty
```
It takes a boolean value and if it's `True`, takes a `()` and puts it in a minimal default context that still succeeds.
@@ -1052,7 +1037,7 @@ ghci> [ x | x <- [1..50], '7' `elem` show x ]
So filtering in list comprehensions is the same as using `guard`.
-### A knight's quest
+### A knight's quest
Here's a problem that really lends itself to being solved with non-determinism.
Say you have a chess board and only one knight piece on it.
@@ -1178,7 +1163,7 @@ It can't check if the monad laws hold for a type though, so if we're making a ne
We can rely on the types that come with the standard library to satisfy the laws, but later when we go about making our own monads, we're going to have to manually check the if the laws hold.
But don't worry, they're not complicated.
-### Left identity
+### Left identity
The first monad law states that if we take a value, put it in a default context with `return` and then feed it to a function by using `>>=`, it's the same as just taking the value and applying the function to it.
To put it formally:
@@ -1211,7 +1196,7 @@ ghci> (\x -> [x,x,x]) "WoM"
We said that for `IO`, using `return` makes an I/O action that has no side-effects but just presents a value as its result.
So it makes sense that this law holds for `IO` as well.
-### Right identity
+### Right identity
The second law states that if we have a monadic value and we use `>>=` to feed it to `return`, the result is our original monadic value.
Formally:
@@ -1245,7 +1230,7 @@ So when we feed `[1,2,3,4]` to `return`, first `return` gets mapped over `[1,2,3
Left identity and right identity are basically laws that describe how `return` should behave.
It's an important function for making normal values into monadic ones and it wouldn't be good if the monadic value that it produced did a lot of other stuff.
-### Associativity
+### Associativity
The final monad law says that when we have a chain of monadic function applications with `>>=`, it shouldn't matter how they're nested.
Formally written: