├── .gitignore
├── LICENSE
├── README.md
├── bin
├── build
├── build-zip
├── release
└── repermission
├── book
├── applicative
│ ├── apply.md
│ ├── chaining.md
│ ├── follow-the-types.md
│ ├── hiding-details.md
│ └── in-the-wild.md
├── book.md
├── functor
│ ├── choices.md
│ ├── curried-form.md
│ ├── functor.md
│ ├── laws.md
│ ├── summary.md
│ ├── type-classes.md
│ └── why.md
├── haskell-basics
│ ├── data-types.md
│ ├── functions.md
│ ├── get-started.md
│ ├── kinds-and-parameters.md
│ └── maybe.md
├── images
│ └── cover.pdf
├── introduction.md
├── monad
│ ├── bind.md
│ ├── do.md
│ ├── intro.md
│ ├── power.md
│ └── wrapping-up.md
├── other-types
│ ├── either.md
│ ├── intro.md
│ ├── io
│ │ ├── intro.md
│ │ ├── main.md
│ │ ├── more.md
│ │ ├── other-instances.md
│ │ └── statements.md
│ └── list.md
├── sample.md
└── whats-next.md
└── release
├── images
├── cover.pdf
├── cover.png
└── fmap.png
├── maybe_haskell.epub
├── maybe_haskell.html
├── maybe_haskell.html.zip
├── maybe_haskell.md
├── maybe_haskell.mobi
├── maybe_haskell.pdf
└── maybe_haskell.toc.html
/.gitignore:
--------------------------------------------------------------------------------
1 | .env
2 | /build/
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | End-User Warranty and License Agreement
2 |
3 | 1. Grant of License
4 | thoughtbot has authorized download by you of one copy of the electronic book
5 | (ebook). thoughtbot grants you a nonexclusive, nontransferable license to use
6 | the ebook according to the terms and conditions herein. This
7 | License Agreement permits you to install the ebook for your use only.
8 |
9 | 2. Restrictions
10 | You shall not: (1) resell, rent, assign, timeshare, distribute, or transfer
11 | all or part of the ebook or any rights granted hereunder to any
12 | other person; (2) duplicate the ebook, except for a single backup
13 | or archival copy; (3) remove any proprietary notices, labels, or marks
14 | from the ebook ; (4) transfer or sublicense title to the ebook
15 | to any other party.
16 |
17 | 3. Intellectual Property Protection
18 | The ebook is owned by thoughtbot and is protected by United States
19 | and international copyright and other intellectual property
20 | laws. thoughtbot reserves all rights in the ebook not expressly
21 | granted herein. This license and your right to use the ebook
22 | terminate automatically if you violate any part of this Agreement. In
23 | the event of termination, you must destroy the original and all copies
24 | of the ebook.
25 |
26 | 4. Limited Warranty
27 | thoughtbot warrants that the files containing the ebook a copy of
28 | which you authorized to download are free from defects in the
29 | operational sense that they can be read by a PDF Reader. EXCEPT FOR
30 | THIS EXPRESS LIMITED WARRANTY, MANNING MAKES AND YOU RECEIVE NO
31 | WARRANTIES, EXPRESS, IMPLIED, STATUTORY OR IN ANY COMMUNICATION WITH
32 | YOU, AND MANNING SPECIFICALLY DISCLAIMS ANY OTHER WARRANTY INCLUDING
33 | THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS OR A PARTICULAR
34 | PURPOSE. MANNING DOES NOT WARRANT THAT THE OPERATION OF THE EBOOK
35 | WILL BE UNINTERRUPTED OR ERROR FREE. If the ebook was purchased in
36 | the United States, the above exclusions may not apply to you as some
37 | states do not allow the exclusion of implied warranties. In addition
38 | to the above warranty rights, you may also have other rights that vary
39 | from state to state.
40 |
41 | 5. Limitation of Liability
42 | IN NO EVENT WILL MANNING BE LIABLE FOR ANY DAMAGES, WHETHER RISING FOR
43 | TORT OR CONTRACT, INCLUDING LOSS OF DATA, LOST PROFITS, OR OTHER
44 | SPECIAL, INCIDENTAL, CONSEQUENTIAL, OR INDIRECT DAMAGES RISING OUT OF
45 | THE USE OR INABILITY TO USE THE EBOOK.
46 |
47 | 6. General
48 | This Agreement constitutes the entire agreement between you and
49 | thoughtbot and supersedes any prior agreement concerning the
50 | ebook. This Agreement is governed by the laws of the Commonwealth of
51 | Massachusetts without reference to conflicts of laws provisions.
52 |
53 | (c) 2013 by thoughtbot
54 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Maybe Haskell
2 |
3 | A book about Haskell's approach to the `null` problem.
4 |
5 | ## Reading the Book
6 |
7 | You can find the current release in a variety of formats under the [release][]
8 | directory. To view older releases, check out a specific Git [tag][tags].
9 |
10 | [release]: https://github.com/thoughtbot/maybe_haskell/tree/master/release
11 | [tags]: https://github.com/thoughtbot/maybe_haskell/releases
12 |
13 | ## Providing Feedback
14 |
15 | Please provide feedback via [GitHub][].
16 |
17 | [github]: https://github.com/thoughtbot/maybe_haskell/issues
18 |
19 | Thank you to all who've [contributed][contributors] so far!
20 |
21 | [contributors]: https://github.com/thoughtbot/maybe_haskell/graphs/contributors
22 |
23 | ## Roadmap
24 |
25 | - [x] Introduction
26 | - [x] Haskell Basics
27 | - [x] Functor
28 | - [x] Applicative
29 | - [x] Monad
30 | - [x] Other Types
31 | - [x] Conclusion
32 | - [x] Technical review
33 | - [x] Copy editing
34 | - [x] Release v1
35 |
--------------------------------------------------------------------------------
/bin/build:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Build all versions into ./build using paperback. Installs the paperback docker
4 | # image if necessary. Uses my fork of paperback, which fixes the build for
5 | # Linux.
6 | #
7 | ###
8 | docker build --tag thoughtbot/paperback https://github.com/pbrisbin/paperback.git
9 | docker run --rm thoughtbot/paperback --version
10 | docker run -v "$PWD":/src thoughtbot/paperback build "$@"
11 |
--------------------------------------------------------------------------------
/bin/build-zip:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | cd build && find \! -name '*-sample*' -exec zip ../maybe_haskell.zip {} +
3 |
--------------------------------------------------------------------------------
/bin/release:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -euo pipefail
3 |
4 | prompt() {
5 | read -r -p "$*? [y/n] " ans
6 |
7 | case "$ans" in
8 | y | Y)
9 | return 0
10 | ;;
11 | esac
12 |
13 | return 1
14 | }
15 |
16 | ./bin/build
17 |
18 | find build \
19 | -mindepth 2 -maxdepth 2 \! -name '*-sample*' \
20 | -exec cp -rv {} release/ \;
21 |
22 | # Relies on zsh rename tool
23 | (cd release && rename src maybe_haskell ./*)
24 |
25 | tag="$(git tag | vbump "${1:-minor}")"
26 |
27 | git status
28 |
29 | if prompt "commit and tag as $tag"; then
30 | git add release
31 | git commit -m "Releasing $tag"
32 | git tag -s -m "$tag" "$tag"
33 |
34 | if prompt 'push'; then
35 | git push --follow-tags
36 | fi
37 | fi
38 |
--------------------------------------------------------------------------------
/bin/repermission:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env stack
2 | {- stack
3 | --resolver lts-8.23
4 | --install-ghc
5 | runghc
6 | --package load-env
7 | --package http-conduit
8 | --package aeson
9 | -- -Wall -Werror
10 | -}
11 | {-# LANGUAGE OverloadedStrings #-}
12 |
13 | module Main (main) where
14 |
15 | import Control.Monad (forM_)
16 | import Control.Monad.Trans.Resource
17 | import Data.Aeson
18 | import Data.ByteString (ByteString)
19 | import Data.Monoid ((<>))
20 | import LoadEnv
21 | import Network.HTTP.Conduit
22 | import System.Environment (getEnv)
23 |
24 | import qualified Data.ByteString.Char8 as C8
25 |
26 | data Permission
27 | = Admin
28 | | Push
29 | | Pull
30 | | None -- ^ Should never actually happen
31 | deriving Eq
32 |
33 | instance FromJSON Permission where
34 | parseJSON = withObject "Permission" $ \o -> fromTriad
35 | <$> o .: "admin"
36 | <*> o .: "push"
37 | <*> o .: "pull"
38 | where
39 | fromTriad True _ _ = Admin
40 | fromTriad _ True _ = Push
41 | fromTriad _ _ True = Pull
42 | fromTriad _ _ _ = None
43 |
44 | instance ToJSON Permission where
45 | toJSON Admin = String "admin"
46 | toJSON Push = String "push"
47 | toJSON Pull = String "pull"
48 | toJSON None = String "none"
49 |
50 | data Collaborator = Collaborator
51 | { coUsername :: String
52 | , coPermission :: Permission
53 | }
54 |
55 | instance FromJSON Collaborator where
56 | parseJSON = withObject "Collaborator" $ \o -> Collaborator
57 | <$> o .: "login"
58 | <*> o .: "permissions"
59 |
60 | instance ToJSON Collaborator where
61 | toJSON c = object ["permission" .= coPermission c]
62 |
63 | canPush :: Collaborator -> Bool
64 | canPush c = coPermission c == Push
65 |
66 | main :: IO ()
67 | main = do
68 | loadEnv
69 | nCollaborators <- run 1 0
70 |
71 | putStrLn $ "Total collaborators: " <> show nCollaborators
72 |
73 | run :: Int -> Int -> IO Int
74 | run n acc = do
75 | putStrLn $ "requesting collaborators, page " <> show n <> "..."
76 | cs <- requestJSON "/collaborators" n id
77 |
78 | if (null cs)
79 | then return acc
80 | else do
81 | forM_ (filter canPush cs) $ \c -> do
82 | putStrLn $ "updating " <> coUsername c <> " to permission:pull..."
83 | requestJSON ("/collaborators/" <> coUsername c) 1
84 | $ setMethod "PUT" . setBody (c { coPermission = Pull }) :: IO ()
85 |
86 | run (n + 1) $ acc + length cs
87 |
88 | requestJSON :: FromJSON a => String -> Int -> (Request -> Request) -> IO a
89 | requestJSON p n f = do
90 | t <- getEnv "GITHUB_ACCESS_TOKEN"
91 | r <- setHeaders t . f <$> parseUrlThrow (requestUrl p n)
92 | m <- newManager tlsManagerSettings
93 | bs <- runResourceT $ responseBody <$> httpLbs r m
94 | return $ either error id $ eitherDecode bs
95 |
96 | requestUrl:: String -> Int -> String
97 | requestUrl p n = "https://api.github.com"
98 | <> "/repos/thoughtbot/maybe_haskell" <> p
99 | <> "?page=" <> show n
100 | <> "&per_page=100"
101 |
102 | setMethod :: ByteString -> Request -> Request
103 | setMethod m r = r { method = m }
104 |
105 | setBody :: ToJSON a => a -> Request -> Request
106 | setBody b r = r { requestBody = RequestBodyLBS $ encode b }
107 |
108 | setHeaders :: String -> Request -> Request
109 | setHeaders token r = r
110 | { requestHeaders =
111 | [ ("Accept", "application/json")
112 | , ("Authorization", "token " <> C8.pack token)
113 | , ("Content-Type", "application/json")
114 | , ("User-Agent", "pbrisbin")
115 | ]
116 | }
117 |
118 | -- vim: ft=haskell
119 |
--------------------------------------------------------------------------------
/book/applicative/apply.md:
--------------------------------------------------------------------------------
1 | ## Apply
2 |
3 | The `(<*>)` operator is pronounced *apply*. Specialized to `Maybe`, its job is
4 | to apply a `Maybe` function to a `Maybe` value to produce a `Maybe` result.
5 |
6 | In our example, we have `fmapUser` of type `Maybe (String -> User)` and
7 | `aMaybeEmail` of type `Maybe String`. We're trying to use `(<*>)` to put those
8 | together and get a `Maybe User`. We can write that down as a type signature:
9 |
10 | ```haskell
11 | (<*>) :: Maybe (String -> User) -> Maybe String -> Maybe User
12 | ```
13 |
14 | With such a specific type, this function won't be very useful, so let's
15 | generalize it away from `String`s and `User`s:
16 |
17 | ```haskell
18 | (<*>) :: Maybe (a -> b) -> Maybe a -> Maybe b
19 | ```
20 |
21 | This function is part of the `Applicative` type class, meaning it will be
22 | defined for many types. Therefore, its actual type signature is:
23 |
24 | ```haskell
25 | (<*>) :: f (a -> b) -> f a -> f b
26 | ```
27 |
28 | Where `f` is any type that has an `Applicative` instance (such as `Maybe`).
29 |
30 | It's important to mention this because it is the type signature you're going to
31 | see in any documentation about `Applicative`. Now that I've done so, I'm going
32 | to go back to type signatures using `Maybe` since that's the specific instance
33 | we're discussing here.
34 |
35 | The semantics of our `(<*>)` function are as follows:
36 |
37 | - If both the `Maybe` function and the `Maybe` value are present, apply the
38 | function to the value and return the result wrapped in `Just`
39 | - Otherwise, return `Nothing`
40 |
41 | We can translate that directly into code via pattern matching:
42 |
43 | ```haskell
44 | (<*>) :: Maybe (a -> b) -> Maybe a -> Maybe b
45 | Just f <*> Just x = Just (f x)
46 | _ <*> _ = Nothing
47 | ```
48 |
49 | With this definition, and a few line breaks for readability, we arrive at our
50 | desired goal:
51 |
52 | ```haskell
53 | userFromParams :: Params -> Maybe User
54 | userFromParams params = User
55 | <$> getParam "name" params
56 | <*> getParam "email" params
57 | ```
58 |
59 | The result is an elegant expression with minimal noise. Compare *that* to the
60 | stair-`case` we started with!
61 |
62 | Not only is this expression elegant, it's also safe. Because of the semantics of
63 | `fmap` and `(<*>)`, if any of the `getParam` calls return `Nothing`, our whole
64 | `userFromParams` expression results in `Nothing`. Only if they all return `Just`
65 | values, do we get `Just` our user.
66 |
67 | As always, Haskell's being referentially transparent means we can prove this by
68 | substituting the definitions of `fmap` and `(<*>)` and tracing how the
69 | expression expands given some example `Maybe` values.
70 |
71 | If the first value is present, but the second is not:
72 |
73 | ```haskell
74 | User <$> Just "Pat" <*> Nothing
75 | -- => fmap User (Just "Pat") <*> Nothing (<$> == fmap)
76 | -- => Just (User "Pat") <*> Nothing (fmap definition, first pattern)
77 | -- => Nothing (<*> definition, second pattern)
78 | ```
79 |
80 | If the second value is present but the first is not:
81 |
82 | ```haskell
83 | User <$> Nothing <*> Just "pat@thoughtbot.com"
84 | -- => fmap User Nothing <*> Just "pat@thoughtbot.com"
85 | -- => Nothing <*> Just "pat@thoughtbot.com" (fmap, second pattern)
86 | -- => Nothing
87 | ```
88 |
89 | Finally, if both values are present:
90 |
91 | ```haskell
92 | User <$> Just "Pat" <*> Just "pat@thoughtbot.com"
93 | -- => fmap User (Just "Pat") <*> Just "pat@thoughtbot.com"
94 | -- => Just (User "Pat") <*> Just "pat@thoughtbot.com"
95 | -- => Just (User "Pat" "pat@thoughtbot.com") (<*>, first pattern)
96 | ```
97 |
--------------------------------------------------------------------------------
/book/applicative/chaining.md:
--------------------------------------------------------------------------------
1 | ## Chaining
2 |
3 | One of the nice things about this pattern is that it scales up to functions
4 | that, conceptually at least, can accept any number of arguments. Imagine that
5 | our `User` type had a third field representing their age:
6 |
7 | ```haskell
8 | data User = User String String Int
9 | ```
10 |
11 | Since our `getParam` function can only look up parameters of type `String`,
12 | we'll also need a `getIntParam` function to pull the user's age out of our
13 | `Params`:
14 |
15 | ```haskell
16 | getIntParam :: String -> Params -> Maybe Int
17 | getIntParam = undefined
18 | ```
19 |
20 | With these defined, let's trace through the types of our applicative expression
21 | again. This time, we have to remember that our new `User` function is of type
22 | `String -> (String -> (Int -> User))`:
23 |
24 | ```haskell
25 | User :: String -> (String -> (Int -> User))
26 |
27 | User <$> getParam "name" params :: Maybe (String -> (Int -> User))
28 |
29 | User <$> getParam "name" params <*> getParam "email" params :: Maybe (Int -> User)
30 | ```
31 |
32 | This time, we arrive at a `Maybe (Int -> User)`. Knowing that `getIntParam "age"
33 | params` is of type `Maybe Int`, we're in the exact same position as last time
34 | when we first discovered a need for `(<*>)`. Being in the same position, we can
35 | do the same thing again:
36 |
37 | ```haskell
38 | userFromParams :: Params -> Maybe User
39 | userFromParams params = User
40 | <$> getParam "name" params
41 | <*> getParam "email" params
42 | <*> getIntParam "age" params
43 | ```
44 |
45 | As our pure function (`User`) gains more arguments, we can continue to apply it
46 | to values in context by repeatedly using `(<*>)`. The process by which this
47 | happens may be complicated, but the result is well worth it: an expression that
48 | is concise, readable, and above all safe.
49 |
--------------------------------------------------------------------------------
/book/applicative/follow-the-types.md:
--------------------------------------------------------------------------------
1 | ## Follow The Types
2 |
3 | We can start by trying to do what we want with the only tool we have so far:
4 | `fmap`.
5 |
6 | What happens when we apply `fmap` to `User`? It's not immediately clear because
7 | `User` has the type `String -> String -> User` which doesn't line up with `(a ->
8 | b)`. Fortunately, it only *appears* not to line up. Remember, every function in
9 | Haskell takes one argument and returns one result: `User`'s actual type is
10 | `String -> (String -> User)`. In other words, it takes a `String` and returns a
11 | function, `(String -> User)`. In this light, it indeed lines up with the type
12 | `(a -> b)` by taking `a` as `String` and `b` as `(String -> User)`.
13 |
14 | By substituting our types for `f`, `a`, and `b`, we can see what the type of
15 | `fmap User` is:
16 |
17 | ```haskell
18 | fmap :: (a -> b) -> f a -> f b
19 |
20 | -- a -> b
21 | User :: String -> (String -> User)
22 |
23 | -- f a -> f b
24 | fmap User :: Maybe String -> Maybe (String -> User)
25 | ```
26 |
27 | So now we have a function that takes a `Maybe String` and returns a `Maybe
28 | (String -> User)`. We also have a value of type `Maybe String` that we can give
29 | to this function, `getParam "name" params`:
30 |
31 | ```haskell
32 | getParam "name" params :: Maybe String
33 |
34 | fmap User :: Maybe String -> Maybe (String -> User)
35 |
36 | fmap User (getParam "name" params) :: Maybe (String -> User)
37 | ```
38 |
39 | The `Control.Applicative` module exports an operator synonym for `fmap` called
40 | `(<$>)` (I pronounce this as *fmap* because that's what it's a synonym for). The
41 | reason this synonym exists is to get us closer to our original goal of making
42 | expressions look as if there are no `Maybe`s involved. Since operators are
43 | placed between their arguments, we can use `(<$>)` to rewrite our
44 | expression above to an equivalent one with less noise:
45 |
46 | ```haskell
47 | User <$> getParam "name" params :: Maybe (String -> User)
48 | ```
49 |
50 | This expression represents a "`Maybe` function". We're accustomed to *values* in a
51 | context: a `Maybe Int`, `Maybe String`, etc; and we saw how these were
52 | *functors*. In this case, we have a *function* in a context: a `Maybe (String ->
53 | User)`. Since functions are things that *can be applied*, these are called
54 | *applicative functors*.
55 |
56 | By using `fmap`, we reduced our problem space and isolated the functionality
57 | we're lacking, functionality we'll ultimately get from `Applicative`:
58 |
59 | We have this:
60 |
61 | ```haskell
62 | fmapUser :: Maybe (String -> User)
63 | fmapUser = User <$> getParam "name" params
64 | ```
65 |
66 | And we have this:
67 |
68 | ```haskell
69 | aMaybeEmail :: Maybe String
70 | aMaybeEmail = getParam "email" params
71 | ```
72 |
73 | And we're trying to ultimately get to this:
74 |
75 | ```haskell
76 | userFromParams :: Maybe User
77 | userFromParams = fmapUser <*> aMaybeEmail
78 | ```
79 |
80 | We only have to figure out what that `(<*>)` should do. At this point, we have
81 | enough things defined that we know exactly what its type needs to be. In the
82 | next section, we'll see how its type pushes us to the correct implementation.
83 |
--------------------------------------------------------------------------------
/book/applicative/hiding-details.md:
--------------------------------------------------------------------------------
1 | In the last section we saw how to use `fmap` to take a system full of functions
2 | that operate on fully present values, free of any `nil`-checks, and employ them
3 | to safely manipulate values that may in fact not be present. This immediately
4 | makes many uses of `Maybe` more convenient, while still being explicit and safe
5 | in the face of failure and partial functions.
6 |
7 | There's another notable case where `Maybe` can cause inconvenience, one that
8 | can't be solved by `fmap` alone. Imagine we're writing some code using a web
9 | framework. It provides a function `getParam` that takes the name of a query
10 | parameter (passed as part of the URL in a GET HTTP request) and returns the
11 | value for that parameter as parsed out of the current URL. Since the parameter
12 | you name could be missing or invalid, this function returns `Maybe`:
13 |
14 | ```haskell
15 | getParam :: String -> Params -> Maybe String
16 | getParam = undefined
17 | ```
18 |
19 | Let's say we also have a `User` data type in our system. `User`s are constructed
20 | from their name and email address, both `String`s.
21 |
22 | ```haskell
23 | data User = User String String
24 | ```
25 |
26 | How do we build a `User` from query params representing their name and email?
27 |
28 | The most direct way is the following:
29 |
30 | ```haskell
31 | userFromParams :: Params -> Maybe User
32 | userFromParams params =
33 | case getParam "name" params of
34 | Just name -> case getParam "email" params of
35 | Just email -> Just (User name email)
36 | Nothing -> Nothing
37 | Nothing -> Nothing
38 | ```
39 |
40 | `Maybe` is not making our lives easier here. Yes, type safety is a huge implicit
41 | win, but this still looks a lot like the tedious, defensive coding you'd find in
42 | any language:
43 |
44 | ```ruby
45 | def user_from_params(params)
46 | if name = get_param "name" params
47 | if email = get_param "email" params
48 | User.new(name, email)
49 | end
50 | end
51 | end
52 | ```
53 |
54 | ## Hiding Details
55 |
56 | So how do we do this better? What we want is code that looks as if there is no
57 | `Maybe` involved (because that's convenient) but correctly accounts for `Maybe`
58 | at every step along the way (because that's safe). If no `Maybe`s
59 | were involved, and we were constructing a normal `User` value, the code might look like
60 | this:
61 |
62 | ```haskell
63 | userFromValues :: User
64 | userFromValues = User aName anEmail
65 | ```
66 |
67 | An ideal syntax would look very similar, perhaps something like this:
68 |
69 | ```haskell
70 | userFromMaybeValues :: Maybe User
71 | userFromMaybeValues = User <$> aMaybeName <*> aMaybeEmail
72 | ```
73 |
74 | The `Applicative` type class and its `Maybe` instance allow us to write exactly
75 | this code. Let's see how.
76 |
--------------------------------------------------------------------------------
/book/applicative/in-the-wild.md:
--------------------------------------------------------------------------------
1 | ## Applicative In the Wild
2 |
3 | This pattern is used in a number of places in the Haskell ecosystem.
4 |
5 | ### JSON parsing
6 |
7 | As one example, the [aeson][] package defines a number of functions for parsing
8 | things out of JSON values. These functions return their results wrapped in a
9 | `Parser` type. This is very much like `Maybe` except that it holds a bit more
10 | information about *why* the computation failed, not only *that* the computation
11 | failed. Not unlike our `getParam`, these sub-parsers pull basic types (`Int`,
12 | `String`, etc.) out of JSON values. The `Applicative` instance for the `Parser`
13 | type can then be used to combine them into something domain-specific, like a
14 | `User`.
15 |
16 | [aeson]: http://hackage.haskell.org/package/aeson
17 |
18 | Again, imagine we had a rich `User` data type:
19 |
20 | ```haskell
21 | data User = User
22 | String -- Name
23 | String -- Email
24 | Int -- Age
25 | UTCTime -- Date of birth
26 | ```
27 |
28 | We can tell aeson how to create a `User` from JSON, by implementing the
29 | `parseJSON` function. That takes a JSON object (represented by the `Value` type)
30 | and returns a `Parser User`:
31 |
32 | ```haskell
33 | parseJSON :: Value -> Parser User
34 | parseJSON (Object o) = User
35 | <$> o .: "name"
36 | <*> o .: "email"
37 | <*> o .: "age"
38 | <*> o .: "birth_date"
39 |
40 | -- If we're given some JSON value besides an Object (an Array, a Number, etc) we
41 | -- can signal failure by returning the special value mzero
42 | parseJSON _ = mzero
43 | ```
44 |
45 | Each individual `o .: "..."` expression is a function that attempts to pull the
46 | value for the given key out of a JSON `Object`. Potential failure (missing key,
47 | invalid type, etc) is captured by returning a value wrapped in the `Parser`
48 | type. We can combine the individual `Parser` values together into one `Parser
49 | User` using `(<$>)` and `(<*>)`.
50 |
51 | If any key is missing, the whole thing fails. If they're all there, we get the
52 | `User` we wanted. This concern is completely isolated within the implementation
53 | of `(<$>)` and `(<*>)` for `Parser`.
54 |
55 | ### Option parsing
56 |
57 | Another example is command-line options parsing via the [optparse-applicative][]
58 | library. The process is very similar: the library exposes low-level parsers for
59 | primitive types like `Flag` or `Argument`. Because this may fail, the values are
60 | wrapped in another `Parser` type. (Though it behaves similarly, this is this
61 | library's own `Parser` type, not the same one as above.) The `Applicative`
62 | instance can again be used to combine these sub-parsers into a domain-specific
63 | `Options` value:
64 |
65 | [optparse-applicative]: https://github.com/pcapriotti/optparse-applicative
66 |
67 | ```haskell
68 | -- Example program options:
69 | --
70 | -- - A bool to indicate if we should be verbose, and
71 | -- - A list of FilePaths to operate on
72 | --
73 | data Options = Options Bool [FilePath]
74 |
75 | parseOptions :: Parser Options
76 | parseOptions = Options
77 | <$> switch (short 'v' <> long "verbose" <> help "be verbose")
78 | <*> many (argument (metavar "FILE" <> help "file to operate on"))
79 | ```
80 |
81 | You can ignore some of the functions here, which were included to keep the
82 | example accurate. What's important is that `switch (...)` is of type `Parser
83 | Bool` and `many (argument ...)` is of type `Parser [FilePath]`. We use `(<$>)`
84 | and `(<*>)` to put these two sub-parsers together with `Options` and end up with
85 | an overall `Parser Options`. If we add more options to our program, all we need
86 | to do is add more fields to `Options` and continue applying sub-parsers with
87 | `(<*>)`.
88 |
--------------------------------------------------------------------------------
/book/book.md:
--------------------------------------------------------------------------------
1 | % Maybe Haskell
2 | % Pat Brisbin
3 |
4 | \clearpage
5 |
6 | # Introduction
7 |
8 | <<[introduction.md]
9 |
10 | \mainmatter
11 |
12 | # Haskell Basics
13 |
14 | <<[haskell-basics/functions.md]
15 |
16 | <<[haskell-basics/data-types.md]
17 |
18 | <<[haskell-basics/kinds-and-parameters.md]
19 |
20 | <<[haskell-basics/maybe.md]
21 |
22 | <<[haskell-basics/get-started.md]
23 |
24 | # Functor
25 |
26 | <<[functor/choices.md]
27 |
28 | <<[functor/type-classes.md]
29 |
30 | <<[functor/functor.md]
31 |
32 | <<[functor/laws.md]
33 |
34 | <<[functor/why.md]
35 |
36 | <<[functor/curried-form.md]
37 |
38 | <<[functor/summary.md]
39 |
40 | # Applicative
41 |
42 | <<[applicative/hiding-details.md]
43 |
44 | <<[applicative/follow-the-types.md]
45 |
46 | <<[applicative/apply.md]
47 |
48 | <<[applicative/chaining.md]
49 |
50 | <<[applicative/in-the-wild.md]
51 |
52 | # Monad
53 |
54 | <<[monad/intro.md]
55 |
56 | <<[monad/power.md]
57 |
58 | <<[monad/bind.md]
59 |
60 | <<[monad/do.md]
61 |
62 | <<[monad/wrapping-up.md]
63 |
64 | # Other Types
65 |
66 | <<[other-types/intro.md]
67 |
68 | <<[other-types/either.md]
69 |
70 | <<[other-types/list.md]
71 |
72 | <<[other-types/io/intro.md]
73 |
74 | <<[other-types/io/statements.md]
75 |
76 | <<[other-types/io/main.md]
77 |
78 | <<[other-types/io/other-instances.md]
79 |
80 | <<[other-types/io/more.md]
81 |
82 | # What's Next
83 |
84 | <<[whats-next.md]
85 |
--------------------------------------------------------------------------------
/book/functor/choices.md:
--------------------------------------------------------------------------------
1 | In the last chapter, we defined a type that allows any value of type `a` to
2 | carry with it additional information about whether it's actually there or not:
3 |
4 | ```haskell
5 | data Maybe a = Nothing | Just a
6 |
7 | actuallyFive :: Maybe Int
8 | actuallyFive = Just 5
9 |
10 | notReallyFive :: Maybe Int
11 | notReallyFive = Nothing
12 | ```
13 |
14 | As you can see, attempting to get at the value inside is dangerous:
15 |
16 | ```haskell
17 | getValue :: Maybe a -> a
18 | getValue (Just x) = x
19 | getValue Nothing = error "uh-oh"
20 |
21 | getValue actuallyFive
22 | -- => 5
23 |
24 | getValue notReallyFive
25 | -- => Runtime error!
26 | ```
27 |
28 | At first, this seems severely limiting: how can we use something if we can't
29 | (safely) get at the value inside?
30 |
31 | ## Choices
32 |
33 | When confronted with some `Maybe a`, and you want to do something with an `a`,
34 | you have three choices:
35 |
36 | 1. Use the value if you can, otherwise throw an exception
37 | 2. Use the value if you can, but still have some way of returning a valid result
38 | if the value's not there
39 | 3. Pass the buck and return a `Maybe` result yourself
40 |
41 | The first option is a non-starter. As you saw, it is possible to throw runtime
42 | exceptions in Haskell via the `error` function, but you should avoid this at all
43 | costs. We're trying to eliminate runtime exceptions, not add them.
44 |
45 | The second option is possible only in certain scenarios. You need to have some
46 | way to handle an incoming `Nothing`. That may mean skipping certain aspects of
47 | your computation or substituting another appropriate value. Usually, if you're
48 | given a completely abstract `Maybe a`, it's not possible to determine a
49 | substitute because you can't produce a value of type `a` out of nowhere.
50 |
51 | Even if you did know the type (say you were given a `Maybe Int`) it would be
52 | unfair to your callers if you defined the safe substitute yourself. In one case
53 | `0` might be best because we're going to add something, but in another `1` would
54 | be better because we plan to multiply. It's best to let them handle it
55 | themselves using a utility function like `fromMaybe`:
56 |
57 | ```haskell
58 | fromMaybe :: a -> Maybe a -> a
59 | fromMaybe x Nothing = x
60 | fromMaybe _ (Just x) = x
61 |
62 | fromMaybe 10 actuallyFive
63 | -- => 5
64 |
65 | fromMaybe 10 notReallyFive
66 | -- => 10
67 | ```
68 |
69 | Option 3 is actually a variation on option 2. By making your own result a
70 | `Maybe` you always have the ability to return `Nothing` yourself if the value isn't present. If the value *is* present, you can perform whatever computation you
71 | need to and wrap what would be your normal result in `Just`.
72 |
73 | The main downside is that now your callers also have to consider how to deal
74 | with the `Maybe`. Given the same situation, they should again make the same
75 | choice (option 3), but that only pushes the problem up to their callers--which means any
76 | `Maybe` values tend to go *viral*.
77 |
78 | Eventually, probably at some UI boundary, someone will need to "deal with" the
79 | `Maybe`, either by providing a substitute or skipping some action that might
80 | otherwise take place. This should happen only once, at that boundary. Every
81 | function between the source and the final use should pass along the value's
82 | potential non-presence unchanged.
83 |
84 | Even though it's safest for every function in our system to pass along a `Maybe`
85 | value, it would be extremely annoying to force them all to actually take and
86 | return `Maybe` values. Each function separately checking whether it should go ahead
87 | and perform its computations will become repetitive and tedious. Instead, we
88 | can completely abstract this "pass along the `Maybe`" concern using higher-order
89 | functions and something called *functors*.
90 |
91 | ## Discovering a Functor
92 |
93 | Imagine we had a higher-order function called `whenJust`:
94 |
95 | ```haskell
96 | whenJust :: (a -> b) -> Maybe a -> Maybe b
97 | whenJust f (Just x) = Just (f x)
98 | whenJust _ Nothing = Nothing
99 | ```
100 |
101 | It takes a function from `a` to `b` and a `Maybe a`. If the value's there, it
102 | applies the function and wraps the result in `Just`. If the value's not there,
103 | it returns `Nothing`. Note that it constructs a new value using the `Nothing`
104 | constructor. This is important because the value we're given is type `Maybe a`
105 | and we must return type `Maybe b`.
106 |
107 | This allows the internals of our system to be made of functions (e.g. the `f`
108 | given to `whenJust`) that take and return normal, non-`Maybe` values, but still
109 | "pass along the `Maybe`" whenever we need to take a value from some source that
110 | may fail and manipulate that value in some way. If it's there, we go ahead and
111 | manipulate it, but return the result as a `Maybe` as well. If it's not, we
112 | return `Nothing` directly.
113 |
114 | ```haskell
115 | whenJust (+5) actuallyFive
116 | -- => Just 10
117 |
118 | whenJust (+5) notReallyFive
119 | -- => Nothing
120 | ```
121 |
122 | This function exists in Haskell's Prelude[^prelude] as `fmap` in the `Functor`
123 | type class.
124 |
125 | [^prelude]: The module of functions available without `import`ing anything.
126 |
--------------------------------------------------------------------------------
/book/functor/curried-form.md:
--------------------------------------------------------------------------------
1 | ## Curried Form
2 |
3 | Before moving on, I need to pause briefly and answer a question I dodged in the
4 | Haskell Basics chapter. You may have wondered why Haskell type signatures don't
5 | separate a function's argument types from its return type. The direct answer is
6 | that all functions in Haskell are in *curried* form. This is an idea developed by and
7 | named for the same [logician][] as Haskell itself.
8 |
9 | [logician]: http://en.wikipedia.org/wiki/Haskell_Curry
10 |
11 | A curried function is one that *conceptually* accepts multiple arguments by
12 | actually accepting only one, but returning a function. The returned function
13 | itself will also be curried and use the same process to accept more arguments.
14 | This process continues for as many arguments as are needed. In short, all functions
15 | in Haskell are of the form `(a -> b)`. A (conceptually) multi-argument function
16 | like `add :: Int -> Int -> Int` is really `add :: Int -> (Int -> Int)`; this
17 | matches `(a -> b)` by taking `a` as `Int` and `b` as `(Int -> Int)`.
18 |
19 | The reason I didn't talk about this earlier is that we can mostly ignore it when
20 | writing Haskell code. We define and apply functions as if they actually accept
21 | multiple arguments and things work as we intuitively expect. Even partial
22 | application (a topic I hand-waved a bit at the time) can be used effectively
23 | without realizing this is a direct result of curried functions. It's when we dive
24 | into concepts like `Applicative` (the focus of the next chapter) that we need to
25 | understand a bit more about what's going on under the hood.
26 |
27 | ### The Case for Currying
28 |
29 | In the implementation of purely functional programming languages, there is value
30 | in having all functions taking exactly one argument and returning exactly one result.
31 | Haskell is written this way, so users have two choices for defining
32 | "multi-argument" functions.
33 |
34 | We could rely solely on tuples:
35 |
36 | ```haskell
37 | add :: (Int, Int) -> Int
38 | add (x, y) = x + y
39 | ```
40 |
41 | This results in the sort of type signatures you might expect, where the argument types are
42 | shown separate from the return types. The problem with this form is that partial
43 | application can be cumbersome. How do you add 5 to every element in a list?
44 |
45 | ```haskell
46 | f :: [Int]
47 | f = map add5 [1,2,3]
48 |
49 | where
50 | add5 :: Int -> Int
51 | add5 y = add (5, y)
52 | ```
53 |
54 | Alternatively, we could write all functions in curried form:
55 |
56 | ```haskell
57 | --
58 | -- / One argument type, an Int
59 | -- |
60 | -- | / One return type, a function from Int to Int
61 | -- | |
62 | add :: Int -> (Int -> Int)
63 | add x = \y -> x + y
64 | -- | |
65 | -- | ` One body expression, a lambda from Int to Int
66 | -- |
67 | -- ` One argument variable, an Int
68 | --
69 | ```
70 |
71 | This makes partial application simpler. Since `add 5` is a valid expression and
72 | is of the correct type to pass to `map`, we can use it directly:
73 |
74 | ```haskell
75 | f :: [Int]
76 | f = map (add 5) [1,2,3]
77 | ```
78 |
79 | While both forms are valid Haskell (in fact, the `curry` and `uncurry` functions
80 | in the Prelude convert functions between the two forms), the curried version was chosen
81 | as the default and so Haskell's syntax allows some things that make it more
82 | convenient.
83 |
84 | For example, we can name function arguments in whatever way we like; we don't
85 | have to always assign a single lambda expression as the function body. In fact,
86 | these are all equivalent:
87 |
88 | ```haskell
89 | add = \x -> \y -> x + y
90 | add x = \y -> x + y
91 | add x y = x + y
92 | ```
93 |
94 | In type signatures, `(->)` is right-associative. This means that instead of
95 | writing:
96 |
97 | ```haskell
98 | addThree :: Int -> (Int -> (Int -> Int))
99 | addThree x y z = x + y + z
100 | ```
101 |
102 | We can write the less-noisy:
103 |
104 | ```haskell
105 | addThree :: Int -> Int -> Int -> Int
106 | addThree x y z = x + y + z
107 | ```
108 |
109 | And it has the same meaning.
110 |
111 | Similarly, function application is left-associative. This means that instead of
112 | writing:
113 |
114 | ```haskell
115 | six :: Int
116 | six = ((addThree 1) 2) 3
117 | ```
118 |
119 | We can write the less-noisy:
120 |
121 | ```haskell
122 | six :: Int
123 | six = addThree 1 2 3
124 | ```
125 |
126 | And it has the same meaning as well.
127 |
128 | These conveniences are why we don't actively picture functions as curried when
129 | writing Haskell code. We can define `addThree` naturally, as if it took three
130 | arguments, and let the rules of the language handle currying. We can also apply
131 | `addThree` naturally, as if it took three arguments and again the rules of the
132 | language will handle the currying.
133 |
134 | ### Partial Application
135 |
136 | Some languages don't use curried functions but do support *partial application*:
137 | supplying only some of a function's arguments to get back another function that
138 | accepts the arguments that were left out. We can do this in Haskell too, but it's not
139 | "partial" at all, since all functions truly accept only a single argument.
140 |
141 | When we wrote the following expression:
142 |
143 | ```haskell
144 | maybeName = fmap userUpperName (findUser someId)
145 | ```
146 |
147 | What really happened is that `fmap` was first applied to the function `userUpperName`
148 | to return a new function of type `Maybe User -> Maybe String`.
149 |
150 | ```haskell
151 | fmap :: (a -> b) -> Maybe a -> Maybe b
152 |
153 | userUpperName :: (User -> String)
154 |
155 | fmap userUpperName :: Maybe User -> Maybe String
156 | ```
157 |
158 | This function is then immediately applied to `(findUser someId)` to ultimately
159 | get that `Maybe String`. This example shows that Haskell's curried functions
160 | blur the line between partial and total application. The result is a natural and
161 | consistent syntax for doing either.
162 |
--------------------------------------------------------------------------------
/book/functor/functor.md:
--------------------------------------------------------------------------------
1 | ## Functor
2 |
3 | Haskell defines the type class `Functor` with a single member function, `fmap`:
4 |
5 | ```haskell
6 | class Functor f where
7 | fmap :: (a -> b) -> f a -> f b
8 | ```
9 |
10 | Type constructors, like `Maybe`, implement `fmap` by defining a function where
11 | that `f` is replaced by themselves. We can see that `whenJust` has the correct
12 | type:
13 |
14 | ```haskell
15 | -- (a -> b) -> f a -> f b
16 | whenJust :: (a -> b) -> Maybe a -> Maybe b
17 | ```
18 |
19 | Therefore, we could implement a `Functor` instance for `Maybe` with the
20 | following code:
21 |
22 | ```haskell
23 | instance Functor Maybe where
24 | fmap = whenJust
25 | ```
26 |
27 | In reality, there is no `whenJust` function; `fmap` is implemented directly:
28 |
29 | ```haskell
30 | instance Functor Maybe where
31 | fmap f (Just x) = Just (f x)
32 | fmap _ Nothing = Nothing
33 | ```
34 |
35 | This definition is exactly like the one we saw earlier for `whenJust`. The only
36 | difference is we're now implementing it as part of the `Functor` instance
37 | declaration for `Maybe`. For the rest of this book, I'll be omitting the `class`
38 | and `instance` syntax. Instead, I'll state in prose when a function is part of
39 | some type class but show its type and definition as if it was a normal,
40 | top-level function.
41 |
--------------------------------------------------------------------------------
/book/functor/laws.md:
--------------------------------------------------------------------------------
1 | ## The Functor Laws
2 |
3 | As mentioned, type class laws are a formal way of defining what it means for
4 | implementations to be "well-behaved." If someone writes a library function and
5 | says it can work with "any `Functor`", that code can rely both on that type
6 | having an `fmap` implementation, and on its operating in accordance with these
7 | laws.
8 |
9 | ### The first Functor law
10 |
11 | The first Functor law states:
12 |
13 | ```haskell
14 | fmap id x == id x
15 | --
16 | -- for any value x, of type f a (e.g. Maybe a)
17 | --
18 | ```
19 |
20 | Where `id` is the *identity* function, one which returns whatever you give it:
21 |
22 | ```haskell
23 | id :: a -> a
24 | id x = x
25 | ```
26 |
27 | Since pure functions always give the same result when given the same input, it's
28 | equally correct to say the functions themselves must be equivalent, rather
29 | than applying them to "any `x`" and saying the results must be equivalent. For
30 | this reason, the laws are usually stated as:
31 |
32 | ```haskell
33 | fmap id == id
34 | ```
35 |
36 | This law says that if we call `fmap id`, the function we get back should be
37 | equivalent to `id` itself. This is what "well-behaved" means in this context. If
38 | you're familiar with the common `map` function on lists, you would expect that
39 | applying `id` to every element in a list (as `map id` does) gives you back the
40 | exact same list. That is exactly what you expect to get if you apply `id`
41 | directly to the list itself. That `map` function is actually `fmap` specialized
42 | to the `[]` type. Hence, that behavior follows from the first law.
43 |
44 | Let's go through the same thought exercise for `Maybe` so you can see that this
45 | law holds for its implementation as well. We'll use our two example values
46 | `actuallyFive` and `notReallyFive` from earlier:
47 |
48 | ```haskell
49 | actuallyFive :: Maybe Int
50 | actuallyFive = Just 5
51 |
52 | notReallyFive :: Maybe Int
53 | notReallyFive = Nothing
54 | ```
55 |
56 | What do we get by applying the identity function to each of these?
57 |
58 | ```haskell
59 | id actuallyFive
60 | -- => Just 5
61 |
62 | id notReallyFive
63 | -- => Nothing
64 | ```
65 |
66 | Not too surprising. Now let's look at `fmap id`:
67 |
68 | ```haskell
69 | fmap id actuallyFive
70 | ```
71 |
72 | Remember the definition of `fmap` for `Maybe` values:
73 |
74 | ```haskell
75 | fmap :: (a -> b) -> Maybe a -> Maybe b
76 | fmap f (Just x) = Just (f x)
77 | fmap _ Nothing = Nothing
78 | ```
79 |
80 | Since `actuallyFive` matches the `Just` case, `fmap` will apply `id` to `5`,
81 | then re-wrap the result in `Just`:
82 |
83 | ```haskell
84 | fmap id actuallyFive
85 | -- => fmap id (Just 5) = Just (id 5)
86 | -- => = Just 5
87 | ```
88 |
89 | And for `notReallyFive`?
90 |
91 | ```haskell
92 | fmap id notReallyFive
93 | ```
94 |
95 | Since `notReallyFive` is `Nothing`, `fmap` will return a new `Nothing`:
96 |
97 | ```haskell
98 | fmap id notReallyFive
99 | -- => fmap _ Nothing = Nothing
100 | -- => = Nothing
101 | ```
102 |
103 | As expected, both results are the same as applying `id` directly.
104 |
105 | ### The second Functor law
106 |
107 | The second law has to do with order of operations. It states:
108 |
109 | ```haskell
110 | fmap (f . g) == fmap f . fmap g
111 | ```
112 |
113 | Where `(.)` is a function that takes two functions and *composes* them together:
114 |
115 | ```haskell
116 | (.) :: (b -> c) -> (a -> b) -> a -> c
117 | (f . g) x = f (g x)
118 | ```
119 |
120 | What this law says is that if we compose two functions together, then `fmap` the
121 | resulting function, we should get a function that behaves the same as when we
122 | `fmap` each function individually, then compose the two results. Let's prove
123 | again that this law holds for `Maybe` by walking through an example with
124 | `actuallyFive` and `notReallyFive`.
125 |
126 | First, let's define two concrete functions, `f` and `g`
127 |
128 | ```haskell
129 | f :: Int -> Int
130 | f = (+2)
131 |
132 | g :: Int -> Int
133 | g = (*3)
134 | ```
135 |
136 | We can *compose* these two functions to get a new function, and call that `h`:
137 |
138 | ```haskell
139 | h :: Int -> Int
140 | h = f . g
141 | ```
142 |
143 | Given the definition of `(.)`, this is equivalent to:
144 |
145 | ```haskell
146 | h :: Int -> Int
147 | h x = f (g x)
148 | ```
149 |
150 | This new function takes a number and gives it to `(*3)`, then it takes the
151 | result and gives it to `(+2)`:
152 |
153 | ```haskell
154 | h 5
155 | -- => 17
156 | ```
157 |
158 | We can give this function to `fmap` to get one that works with `Maybe` values:
159 |
160 | ```haskell
161 | fmap h actuallyFive
162 | -- => Just 17
163 |
164 | fmap h notReallyFive
165 | -- => Nothing
166 | ```
167 |
168 | Similarly, we can give each of `f` and `g` to `fmap` separately to produce
169 | functions that can add 2 or multiply 3 to a `Maybe Int` and produce another
170 | `Maybe Int`. The resulting functions can also be composed with `(.)` to produce
171 | a new function, `fh`:
172 |
173 | ```haskell
174 | fh :: Maybe Int -> Maybe Int
175 | fh = fmap f . fmap g
176 | ```
177 |
178 | Again, given the definition of `(.)`, this is equivalent to:
179 |
180 | ```haskell
181 | fh :: Maybe Int -> Maybe Int
182 | fh x = fmap f (fmap g x)
183 | ```
184 |
185 | This function will call `fmap g` on its argument, which will multiply by 3 if the
186 | number's there or return `Nothing` if it's not. Then it will give that result to `fmap f`, which will add 2 if the number's there, or return `Nothing` if it's not:
187 |
188 | ```haskell
189 | fh actuallyFive
190 | -- => Just 17
191 |
192 | fh notReallyFive
193 | -- => Nothing
194 | ```
195 |
196 | You should convince yourself that `fh` and `fmap h` behave in exactly the same
197 | way. The second functor law states that this must be the case if your type is to
198 | be a valid `Functor`.
199 |
200 | Because Haskell is referentially transparent, we can freely replace functions with
201 | their implementations. It may require some explicit parentheses here
202 | and there, but the code will always give the same answer. Doing so brings us
203 | back directly to the statement of the second law:
204 |
205 | ```haskell
206 | (fmap f . fmap g) actuallyFive
207 | -- => Just 17
208 |
209 | fmap (f . g) actuallyFive
210 | -- => Just 17
211 |
212 | (fmap f . fmap g) notReallyFive
213 | -- => Nothing
214 |
215 | fmap (f . g) notReallyFive
216 | -- => Nothing
217 |
218 | -- Therefore:
219 | fmap (f . g) == fmap f . fmap g
220 | ```
221 |
222 | Not only can we take normal functions (those that operate on fully present
223 | values) and give them to `fmap` to get functions that can operate on `Maybe` values,
224 | but this law states we can do so in any order. We can compose our system of
225 | functions together *then* give that to `fmap` or we can `fmap` individual
226 | functions and compose *those* together. Either way, we're guaranteed to get the same
227 | result. We can rely on this fact whenever we use `fmap` for any type that's in
228 | the `Functor` type class.
229 |
--------------------------------------------------------------------------------
/book/functor/summary.md:
--------------------------------------------------------------------------------
1 | ## Recap
2 |
3 | So far, we've seen an introduction to Haskell functions and to Haskell's type
4 | system. We then introduced the `Maybe` type as a new and powerful way to use
5 | that type system to describe something about your domain--that some values may
6 | not be present--and a type class (`Functor`) that allows for strict separation
7 | between value-handling functions and the need to apply them to values that may
8 | not be present.
9 |
10 | We then saw some real-world code that takes advantage of these ideas and
11 | discussed type class laws as a means of abstraction and encapsulation. These
12 | laws give us a precise understanding of how our code will behave without having
13 | to know its internals. Finally, we took a brief detour into the world of
14 | currying, a foundational concept responsible for many of the things we'll
15 | explore next.
16 |
17 | In the next chapter, we'll talk about *applicative functors*. If we think of a
18 | *functor* as a value in some context, supporting an `fmap` operation for
19 | applying a function to that value while preserving its context, *applicative
20 | functors* are functors where the value itself *can be applied*. In simple terms:
21 | it's a function. These structures must then support another operation for
22 | applying that function from within its context. That operation, combined with
23 | currying, will grant us more power and convenience when working with `Maybe`
24 | values.
25 |
--------------------------------------------------------------------------------
/book/functor/type-classes.md:
--------------------------------------------------------------------------------
1 | ## About Type Classes
2 |
3 | Haskell has a concept called *type classes*. These are not at all related to the
4 | classes used in Object-oriented programming. Instead, Haskell uses type classes
5 | for functions that may be implemented in different ways for different data
6 | types. These are more like the *interfaces* and *protocols* you may find in
7 | other languages. For example, we can add or negate various kinds of numbers:
8 | integers, floating points, rational numbers, etc. To accommodate this, Haskell
9 | has a [`Num`][] type class that includes functions like `(+)` and `negate`.
10 | Each concrete type (`Int`, `Float`, etc) then defines its own version of the
11 | required functions.
12 |
13 | [`Num`]: http://hackage.haskell.org/package/base-4.7.0.1/docs/Prelude.html#t:Num
14 |
15 | Type classes are defined with the `class` keyword and a `where` clause listing
16 | the types of any *member functions*:
17 |
18 | ```haskell
19 | class Num a where
20 | (+) :: a -> a -> a
21 |
22 | negate :: a -> a
23 | ```
24 |
25 | Being an *instance* of a type class requires that you implement any member functions
26 | with the correct type signatures. To make `Int` an instance of `Num`, someone
27 | defined the `(+)` and `negate` functions for it. This is done with the
28 | `instance` keyword and a `where` clause that implements the functions from the
29 | class declaration:
30 |
31 | ```haskell
32 | instance Num Int where
33 | x + y = addInt x y
34 |
35 | negate x = negateInt x
36 | ```
37 |
38 | Usually, but not always, *laws* are associated with these functions that
39 | your implementations must satisfy. Type class laws are important for ensuring that type classes are useful. They allow us as developers to reason about what will happen
40 | when we use type class functions without having to understand all of the
41 | concrete types for which they are defined. For example, if you negate a number
42 | twice, you should get back to the same number. This can be stated formally as:
43 |
44 | ```haskell
45 | negate (negate x) == x -- for any x
46 | ```
47 |
48 | Knowing that this law holds gives us a precise understanding of what will happen
49 | when we use `negate`. Because of the laws, we get this understanding without
50 | having to know how `negate` is implemented for various types. This is a simple example,
51 | but we'll see more interesting laws with the `Functor` type class.
52 |
--------------------------------------------------------------------------------
/book/functor/why.md:
--------------------------------------------------------------------------------
1 | ## Why Is This Useful?
2 |
3 | OK, enough theory. Now that we know how it works, let's see how it's used. Say
4 | we have a lookup function to get from a `UserId` to the `User` for that id.
5 | Since the user may not exist, it returns a `Maybe User`:
6 |
7 | ```haskell
8 | findUser :: UserId -> Maybe User
9 | findUser = undefined
10 | ```
11 |
12 | I've left the implementation of `findUser` as `undefined` because this doesn't
13 | matter for our example. I'll do this frequently throughout the book. `undefined`
14 | is a function with type `a`. That allows it to stand in for any expression. If
15 | your program ever tries to evaluate it, it will raise an exception. Still, it
16 | can be extremely useful while developing because we can build our program
17 | incrementally, but have the compiler check our types as we go.
18 |
19 | Next, imagine we want to display a user's name in all capitals:
20 |
21 | ```haskell
22 | userUpperName :: User -> String
23 | userUpperName u = map toUpper (userName u)
24 | ```
25 |
26 | The logic of getting from a `User` to that capitalized `String` is not terribly
27 | complex, but it could be. Imagine something like getting from a `User` to
28 | that user's yearly spending on products valued over $1,000. In our case the
29 | transformation is only one function, but realistically it could be a whole suite
30 | of functions wired together. Ideally, none of these functions should have to
31 | think about potential non-presence or contain any "nil-checks," as that's not
32 | their purpose; they should all be written to work on values that are fully
33 | present.
34 |
35 | Given `userUpperName`, which works only on present values, we can use `fmap` to
36 | apply it to a value that may not be present to get back the result we expect
37 | with the same level of *present-ness*:
38 |
39 | ```haskell
40 | maybeName :: Maybe String
41 | maybeName = fmap userUpperName (findUser someId)
42 | ```
43 |
44 | We can do this repeatedly with every function in our system that's required to
45 | get from `findUser` to the eventual display of this name. Because of the second
46 | functor law, we know that if we compose all of these functions together then
47 | `fmap` the result, or if we `fmap` any individual functions and compose the
48 | results, we'll always get the same answer. We're free to design our system as we
49 | see fit, but still pass along the `Maybe`s everywhere we need to.
50 |
51 | If we were doing this in the context of a web application, this maybe-name might
52 | end up being interpolated into some HTML. It's at this boundary that we'll have
53 | to "deal with" the `Maybe` value. One option is to use the `fromMaybe` function
54 | to specify a default value:
55 |
56 | ```haskell
57 | template :: Maybe String -> String
58 | template mname = "" ++ name ++ ""
59 |
60 | where
61 | name = fromMaybe "(no name given)" mname
62 | ```
63 |
--------------------------------------------------------------------------------
/book/haskell-basics/data-types.md:
--------------------------------------------------------------------------------
1 | ## Our Own Data Types
2 |
3 | We're not limited to basic types like `Int` or `String`. As you might expect,
4 | Haskell allows you to define custom data types:
5 |
6 | ```haskell
7 | data Person = MakePerson String Int
8 | -- | |
9 | -- | ` The persons's age
10 | -- |
11 | -- ` The person's name
12 | ```
13 |
14 | To the left of the `=` is the *type* constructor and to the right can be one or
15 | more *data* constructors. The type constructor is the name of the type, which is
16 | used in type signatures. The data constructors are functions that produce
17 | values of the given type. For example, `MakePerson` is a function that takes a
18 | `String` and an `Int`, and returns a `Person`. Note that I will often use the
19 | general term "constructor" to refer to a *data* constructor if the meaning is
20 | clear from the context.
21 |
22 | When working with only one data constructor, it's quite common to give it the same
23 | name as the type constructor. This is because it's syntactically impossible to
24 | use one in place of the other, so the compiler makes no restriction. Naming is
25 | hard. So when you have a good name, you might as well use it in both contexts.
26 |
27 | ```haskell
28 | data Person = Person String Int
29 | -- | |
30 | -- | ` Data constructor
31 | -- |
32 | -- ` Type constructor
33 | ```
34 |
35 | Once we have declared the data type, we can now use it to write functions that
36 | construct values of this type:
37 |
38 | ```haskell
39 | pat :: Person
40 | pat = Person "Pat" 29
41 | ```
42 |
43 | ## Pattern Matching
44 |
45 | To get the individual parts back out again, we use [pattern
46 | matching][pattern-matching]:
47 |
48 | ```haskell
49 | getName :: Person -> String
50 | getName (Person name _) = name
51 |
52 | getAge :: Person -> Int
53 | getAge (Person _ age) = age
54 | ```
55 |
56 | In the definitions above, each function is looking for values constructed with
57 | `Person`. If it gets an argument that matches (which is guaranteed since that's
58 | the only way to get a `Person` in our system so far), Haskell will use that
59 | function body with each part of the constructed value bound to the variables
60 | given. The `_` pattern (called a *wildcard*) is used for any parts we don't care
61 | about. Again, this is using `=` for equivalence (as always). We're saying that
62 | `getName`, when given `(Person name _)`, *is equivalent to* `name`. It works
63 | similarly for `getAge`.
64 |
65 | Haskell offers [other][records] [ways][lenses] to do this sort of thing, but we won't
66 | get into those here.
67 |
68 | [pattern-matching]: https://www.haskell.org/tutorial/patterns.html
69 | [records]: http://en.wikibooks.org/wiki/Haskell/More_on_datatypes#Named_Fields_.28Record_Syntax.29
70 | [lenses]: http://www.haskellforall.com/2012/01/haskell-for-mainstream-programmers_28.html
71 |
72 | ## Sum Types
73 |
74 | As mentioned earlier, types can have more than one data constructor. These are
75 | called *sum types* because the total number of values you can build of a sum
76 | type is the sum of the number of values you can build with each of its
77 | constructors. The syntax is to separate each constructor by a `|` symbol:
78 |
79 | ```haskell
80 | data Person = PersonWithAge String Int | PersonWithoutAge String
81 |
82 | pat :: Person
83 | pat = PersonWithAge "Pat" 29
84 |
85 | jim :: Person
86 | jim = PersonWithoutAge "Jim"
87 | ```
88 |
89 | Notice that `pat` and `jim` are both values of type `Person`, but they've been
90 | constructed differently. We can use pattern matching to inspect how a value was
91 | constructed and accordingly choose what to do. Syntactically, this is
92 | accomplished by providing multiple definitions of the same function, each
93 | matching a different pattern. Each definition will be tried in the order
94 | defined, and the first function to match will be used.
95 |
96 | This works well for pulling the name out of a value of our new `Person` type:
97 |
98 | ```haskell
99 | getName :: Person -> String
100 | getName (PersonWithAge name _) = name
101 | getName (PersonWithoutAge name) = name
102 | ```
103 |
104 | But we must be careful when trying to pull out a person's age:
105 |
106 | ```haskell
107 | getAge :: Person -> Int
108 | getAge (PersonWithAge _ age) = age
109 | getAge (PersonWithoutAge _) = -- uh-oh
110 | ```
111 |
112 | If we decide to be lazy and not define that second function body, Haskell will
113 | compile, but warn us about a *non-exhaustive* pattern match. What we've
114 | created at that point is a *partial function*. If such a program ever attempts
115 | to match `getAge` with a `Person` that has no age, we'll see one of the few
116 | runtime errors possible in Haskell.
117 |
118 | A person's name is always there, but their age may or may not be. Defining two
119 | constructors makes both cases explicit and forces anyone attempting to access a
120 | person's age to deal with its potential non-presence.
121 |
--------------------------------------------------------------------------------
/book/haskell-basics/functions.md:
--------------------------------------------------------------------------------
1 | When we declare a function in Haskell, we first write a type signature:
2 |
3 | ```haskell
4 | five :: Int
5 | ```
6 |
7 | We can read this as `five` *of type* `Int`.
8 |
9 | Next, we write a definition:
10 |
11 | ```haskell
12 | five = 5
13 | ```
14 |
15 | We can read this as `five` *is* `5`.
16 |
17 | In Haskell, `=` is not variable assignment, it's defining equivalence. We're
18 | saying here that the word `five` *is equivalent to* the literal `5`. Anywhere
19 | you see one, you can replace it with the other and the program will always give
20 | the same answer. This property is called *referential transparency* and it holds
21 | true for any Haskell definition, no matter how complicated.
22 |
23 | It's also possible to specify types with an *annotation* rather than a
24 | signature. We can annotate any expression with `:: ` to explicitly tell
25 | the compiler the type we want (or expect) that expression to have.
26 |
27 | ```haskell
28 | almostThird = (3 :: Float) / 9
29 | -- => 0.3333334
30 |
31 | actualThird = (3 :: Rational) / 9
32 | -- => 1 % 3
33 | ```
34 |
35 | We can read these as `almostThird` is `3`, *of type* `Float`, divided by `9` and
36 | `actualThird` is `3`, *of type* `Rational`, divided by `9`.
37 |
38 | Type annotations and signatures are usually optional, as Haskell can almost
39 | always tell the type of an expression by inspecting the types of its constituent
40 | parts or seeing how it is eventually used. This process is called *type
41 | inference*. For example, Haskell knows that `actualThird` is a `Rational`
42 | because it saw that `3` is a `Rational`. Since you can only use `(/)` with
43 | arguments of the same type, it *enforced* that `9` is also a `Rational`. Knowing
44 | that `(/)` returns the same type as its arguments, the final result of the
45 | division must itself be a `Rational`.
46 |
47 | Good Haskellers will include a type signature on all top-level definitions
48 | anyway. It provides executable documentation and may, in some cases, prevent
49 | errors that occur when the compiler assigns a more generic type than you might
50 | otherwise want.
51 |
52 | ### Arguments
53 |
54 | Defining functions that take arguments looks like this:
55 |
56 | ```haskell
57 | add :: Int -> Int -> Int
58 | add x y = x + y
59 | ```
60 |
61 | The type signature can be confusing because the argument types are not separated
62 | from the return type. There is a good reason for this, but I won't go into it
63 | yet. For now, feel free to mentally treat the thing after the last arrow as the
64 | return type.
65 |
66 | After the type signature, we give the function's name (`add`) and names for any
67 | arguments it takes (`x` and `y`). On the other side of the `=`, we define an
68 | expression using those names.
69 |
70 | ### Higher-order functions
71 |
72 | Functions can take and return other functions. These are known as
73 | [higher-order][] functions. In type signatures, any function arguments or return
74 | values must be surrounded by parentheses:
75 |
76 | [higher-order]: http://learnyouahaskell.com/higher-order-functions
77 |
78 | ```haskell
79 | twice :: (Int -> Int) -> Int -> Int
80 | twice f x = f (f x)
81 |
82 | twice (add 2) 3
83 | -- => 7
84 | ```
85 |
86 | `twice` takes as its first argument a function of type `(Int -> Int)`. As its
87 | second argument, it takes an `Int`. The body of the function applies the first
88 | argument (`f`) to the second (`x`) twice, returning another `Int`. The
89 | parentheses in the definition of `twice` indicate grouping, not application. In
90 | Haskell, applying a function to some argument is simple: stick them together
91 | with a space in between. In this case, we need to group the inner `(f x)` so the
92 | outer `f` is applied to it as single argument. Without these parentheses,
93 | Haskell would think we were applying `f` to two arguments: another `f` and `x`.
94 |
95 | You also saw an example of *partial application*. The expression `add 2` returns
96 | a new function that itself takes the argument we left off. Let's break down that
97 | last expression to see how it works:
98 |
99 | ```haskell
100 | -- Add takes two Ints and returns an Int
101 | add :: Int -> Int -> Int
102 | add x y = x + y
103 |
104 | -- Supplying only the first argument gives us a new function that will add 2 to
105 | -- its argument. Its type is Int -> Int
106 | add 2 :: Int -> Int
107 |
108 | -- Which is exactly the type of twice's first argument
109 | twice :: (Int -> Int) -> Int -> Int
110 | twice f x = f (f x)
111 |
112 | twice (add 2) 3
113 | -- => add 2 (add 2 3)
114 | -- => add 2 5
115 | -- => 7
116 | ```
117 |
118 | It's OK if this doesn't make complete sense now. I'll talk more about partial
119 | application as we go.
120 |
121 | ### Operators
122 |
123 | In the definition of `add`, I used something called an *operator*: `(+)`.
124 | Operators like this are not in any way special or built-in; we can define and
125 | use them like any other function. That said, operators have three additional (and
126 | convenient) behaviors:
127 |
128 | 1. They are used *infix* by default, meaning they appear between their arguments
129 | (i.e. `2 + 2`, not `+ 2 2`). To use an operator *prefix*, it must be
130 | surrounded in parentheses (as in `(+) 2 2`).
131 | 2. When defining an operator, we can assign custom [associativity][] and
132 | [precedence][] relative to other operators. This tells Haskell how to group
133 | expressions like `2 + 3 * 5 / 10`.
134 | 3. We can surround an operator and *either* of its arguments in parentheses to
135 | get a new function that accepts whichever argument we left off. Expressions
136 | like `(+ 2)` and `(10 /)` are examples. The former adds `2` to something and
137 | the latter divides `10` by something. Expressions like these are called
138 | *sections*.
139 |
140 | [associativity]: http://en.wikipedia.org/wiki/Associative_property
141 | [precedence]: http://en.wikipedia.org/wiki/Order_of_operations
142 |
143 | In Haskell, any function with a name made up entirely of punctuation (where [The
144 | Haskell Report][report] states very precisely what "punctuation" means) behaves
145 | like an operator. We can also take any normally named function and treat it like
146 | an operator by surrounding it in backticks:
147 |
148 | [report]: https://www.haskell.org/onlinereport/haskell2010/haskellch2.html#x7-160002.2
149 |
150 | ```haskell
151 | -- Normal usage of an elem function for checking if a value is present in a list
152 | elem 3 [1, 2, 3, 4, 5]
153 | -- => True
154 |
155 | -- Reads a little better infix
156 | 3 `elem` [1, 2, 3, 4, 5]
157 | -- => True
158 |
159 | -- Or as a section, leaving out the first argument
160 | intersects xs ys = any (`elem` xs) ys
161 | ```
162 |
163 | ### Lambdas
164 |
165 | The last thing we need to know about functions is that they can be *anonymous*.
166 | Anonymous functions are called *lambdas* and are most frequently used as
167 | arguments to higher-order functions. Often these functional arguments exist
168 | for only a single use and giving them a name is not otherwise valuable.
169 |
170 | The syntax is a back-slash, followed by the arguments to the function, an arrow, and finally the
171 | body of the function. A back-slash is used because it looks similar to the Greek
172 | letter λ.
173 |
174 | Here's an example:
175 |
176 | ```haskell
177 | twice (\x -> x * x + 10) 5
178 | -- => 1235
179 | ```
180 |
181 | If you come across a code example using a lambda, you can always rewrite it to
182 | use named functions. Here's the process for this example:
183 |
184 | ```haskell
185 | -- Grab the lambda
186 | \x -> x * x + 10
187 |
188 | -- Name it
189 | f = \x -> x * x + 10
190 |
191 | -- Replace "\... ->" with normal arguments
192 | f x = x * x + 10
193 |
194 | -- Use the name instead
195 | twice f 5
196 | ```
197 |
--------------------------------------------------------------------------------
/book/haskell-basics/get-started.md:
--------------------------------------------------------------------------------
1 | ## Don't Give Up
2 |
3 | The above might leave you feeling underwhelmed. That code doesn't look all that
4 | better than the equivalent Ruby:
5 |
6 | ```ruby
7 | def find_user(uid)
8 | if user = all_users.detect? { |u| u.matches_id?(uid) }
9 | user
10 | else
11 | # what to do? error?
12 | end
13 | end
14 | ```
15 |
16 | First of all, the Haskell version is type safe: `findUser` must always return a
17 | `User` since that's the type we've specified. I'd put money on most Ruby
18 | developers returning `nil` from the `else` branch. The Haskell type system won't
19 | allow that and that's a good thing. Otherwise, we have these values floating
20 | throughout our system that we assume are there and in fact are not. I understand
21 | that without spending time programming in Haskell, it's hard to see the benefits
22 | of ruthless type safety employed at every turn. I assure you it's a coding
23 | experience like no other, but I'm not here to convince you of that -- at least
24 | not directly.
25 |
26 | The bottom line is that an experienced Haskeller would not write this code this
27 | way. `case` is a code smell when it comes to `Maybe`. Almost all code using
28 | `Maybe` can be improved from a tedious `case` evaluation using one of the three
29 | abstractions we'll explore in this book.
30 |
31 | Let's get started.
32 |
--------------------------------------------------------------------------------
/book/haskell-basics/kinds-and-parameters.md:
--------------------------------------------------------------------------------
1 | ## Kinds and Parameters
2 |
3 | Imagine we wanted to generalize this `Person` type. What if people were able to
4 | hold arbitrary things? What if what that thing is (its type) doesn't really
5 | matter, if the only meaningful thing we can say about it is if it's there or not?
6 | What we had before was a *person with an age* or a *person without an age*. What
7 | we want now is a *person with a thing* or a *person without a thing*.
8 |
9 | One way to do this is to *parameterize* the type:
10 |
11 | ```haskell
12 | data Person a = PersonWithThing String a | PersonWithoutThing String
13 | -- | |
14 | -- | ` we can use it as an argument here
15 | -- |
16 | -- ` By adding a "type variable" here
17 | ```
18 |
19 | The type we've defined here is `Person a`. We can construct values of type
20 | `Person a` by giving a `String` and an `a` to `PersonWithThing`, or by giving
21 | only a `String` to `PersonWithoutThing`. Notice that even if we build our person
22 | using `PersonWithoutThing`, the constructed value still has type `Person a`.
23 |
24 | The `a` is called a *type variable*. Any lowercase value will do, but it's
25 | common to use `a` because it's short, and a value of type `a` can be thought of
26 | as a value of *any* type. Rather than hard-coding that a person has an `Int`
27 | representing their age (or not), we can say a person is holding some thing of
28 | type `a` (or not).
29 |
30 | We can still construct people with and without ages, but now we have to specify
31 | in the type that in this case the `a` is an `Int`:
32 |
33 | ```haskell
34 | patWithAge :: Person Int
35 | patWithAge = PersonWithThing "pat" 29
36 |
37 | patWithoutAge :: Person Int
38 | patWithoutAge = PersonWithoutThing "pat"
39 | ```
40 |
41 | Notice how even in the case where I have no age, we still specify the type of
42 | that thing that I do not have. In this case, we specified an `Int` for
43 | `patWithoutAge`, but values can have (or not have) any type of thing:
44 |
45 | ```haskell
46 | patWithEmail :: Person String
47 | patWithEmail = PersonWithThing "pat" "pat@thoughtbot.com"
48 |
49 | patWithoutEmail:: Person String
50 | patWithoutEmail = PersonWithoutThing "pat"
51 | ```
52 |
53 | We don't have to give a concrete `a` when it doesn't matter. `patWithoutAge` and
54 | `patWithoutEmail` are the same value with different types. We could define a
55 | single value with the generic type `Person a`:
56 |
57 | ```haskell
58 | patWithoutThing :: Person a
59 | patWithoutThing = PersonWithoutThing "pat"
60 | ```
61 |
62 | Because `a` is more general than `Int` or `String`, a value such as this can
63 | stand in anywhere a `Person Int` or `Person String` is needed:
64 |
65 | ```haskell
66 | patWithoutAge :: Person Int
67 | patWithoutAge = patWithoutThing
68 |
69 | patWithoutEmail :: Person String
70 | patWithoutEmail = patWithoutThing
71 | ```
72 |
73 | Similarly, functions that operate on people can choose whether they care about what
74 | the person's holding--or not. For example, getting someone's name shouldn't be
75 | affected by whether they hold something, so we can leave it unspecified:
76 |
77 | ```haskell
78 | getName :: Person a -> String
79 | getName (PersonWithThing name _) = name
80 | getName (PersonWithoutThing name) = name
81 |
82 | getName patWithAge
83 | -- => "pat"
84 |
85 | getName patWithoutEmail
86 | -- => "pat"
87 | ```
88 |
89 | But a function that does care must specify both the type *and* account for the
90 | case of non-presence:
91 |
92 | ```haskell
93 | doubleAge :: Person Int -> Int
94 | doubleAge (PersonWithThing _ age) = 2 * age
95 | doubleAge (PersonWithoutThing _) = 1
96 |
97 | doubleAge patWithAge
98 | -- => 58
99 |
100 | doubleAge patWithoutAge
101 | -- => 1
102 |
103 | doubleAge patWithoutThing
104 | -- => 1
105 |
106 | doubleAge patWithoutEmail
107 | -- => Type error! Person String != Person Int
108 | ```
109 |
110 | In this example, `doubleAge` had to account for people that had no age. The
111 | solution it chose was a poor one: return the doubled age or `1`. A better choice
112 | is to not return an `Int`; instead, return some type capable of holding both the
113 | doubled age and the fact that we might not have had an age to double in the
114 | first place. What we need is `Maybe`.
115 |
--------------------------------------------------------------------------------
/book/haskell-basics/maybe.md:
--------------------------------------------------------------------------------
1 | ## Maybe
2 |
3 | Haskell's `Maybe` type is very similar to our `Person` example:
4 |
5 | ```haskell
6 | data Maybe a = Nothing | Just a
7 | ```
8 |
9 | The difference is that we're not dragging along a name this time. This type is only
10 | concerned with representing a value (of any type) that is either *present* or
11 | *not*.
12 |
13 | We can use this to take functions that otherwise would be *partial* and make
14 | them *total*:
15 |
16 | ```haskell
17 | -- | Find the first element from the list for which the predicate function
18 | -- returns True. Return Nothing if there is no such element.
19 | find :: (a -> Bool) -> [a] -> Maybe a
20 | find _ [] = Nothing
21 | find predicate (first:rest) =
22 | if predicate first
23 | then Just first
24 | else find predicate rest
25 | ```
26 |
27 | This function has two definitions matching two different patterns: if given the
28 | empty list, we immediately return `Nothing`. Otherwise, the (non-empty) list is
29 | de-constructed into its `first` element and the `rest` of the list by matching
30 | on the `(:)` (pronounced *cons*) constructor. Then we test whether applying the
31 | `predicate` function to `first` returns `True`. If it does, we return `Just` that.
32 | Otherwise, we recurse and try to find the element in the `rest` of the list.
33 |
34 | Returning a `Maybe` value forces all callers of `find` to deal with the
35 | potential `Nothing` case:
36 |
37 | ```haskell
38 | --
39 | -- Warning: this is a type error, not working code!
40 | --
41 | findUser :: UserId -> User
42 | findUser uid = find (matchesId uid) allUsers
43 | ```
44 |
45 | This is a type error since the expression actually returns a `Maybe User`.
46 | Instead, we have to take that `Maybe User` and inspect it to see if something's
47 | there or not. We can do this via `case`, which also supports pattern matching:
48 |
49 | ```haskell
50 | findUser :: UserId -> User
51 | findUser uid =
52 | case find (matchesId uid) allUsers of
53 | Just u -> u
54 | Nothing -> -- what to do? error?
55 | ```
56 |
57 | Depending on your domain and the likelihood of Maybe values, you might find this
58 | sort of "stair-casing" propagating throughout your system. This can lead to the
59 | thought that `Maybe` isn't really all that valuable over some *null* value built
60 | into the language. If you need these `case` expressions peppered throughout the
61 | code base, how is that better than the analogous "`nil` checks"?
62 |
--------------------------------------------------------------------------------
/book/images/cover.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtbot/maybe_haskell/af2130d3e040ba15281141360210c525f70fb0ca/book/images/cover.pdf
--------------------------------------------------------------------------------
/book/introduction.md:
--------------------------------------------------------------------------------
1 | As a programmer, I spend a lot of time dealing with the fallout from one
2 | specific problem: partial functions. A partial function is one that can't
3 | provide a valid result for all possible inputs. If you write a function (or
4 | method) to return the first element in an array that satisfies some condition,
5 | what do you do if no such element exists? You've been given an input for which
6 | you can't return a valid result. Aside from raising an exception, what can you
7 | do?
8 |
9 | The most popular way to to deal with this is to return a special value that
10 | indicates failure. Ruby has `nil`, Java has `null`, and many C functions return
11 | `-1` in failure cases. This is a huge hassle. You now have a system in which any
12 | value at any time can either be the value you expect or `nil`, always.
13 |
14 | For instance, if you try to find a `User`, and then treat the value you get back
15 | as if it's a `User` but it's actually `nil`, you get a `NoMethodError`. What's
16 | worse, that error may not happen anywhere near the problem's source. The line of
17 | code that created that `nil` may not even appear in the eventual backtrace. The
18 | result is various "`nil` checks" peppered throughout the code. Is this the best
19 | we can do?
20 |
21 | The problem of partial functions is not going away. User input may be invalid,
22 | files may not exist, networks may fail. We will always need a way to deal with
23 | partial functions. What we don't need is `null`.
24 |
25 | ## An Alternate Solution
26 |
27 | In languages with sufficiently expressive type systems, we have another option:
28 | we can state in the types that certain values may not be present. Functions that
29 | typically are written in a partial way can instead be defined to return a type
30 | that captures any potential non-presence. Not only does this make it explicit
31 | and "type checked" that you have code to handle the case when a value isn't
32 | present, it also means that if a value is *not* of this special "nullable" type,
33 | you can feel safe in assuming the value is really there. In short: no `nil`
34 | checks are required.
35 |
36 | The focus of this book will be how Haskell implements this idea via the
37 | `Maybe` data type. This type and all the functions that deal with it are not
38 | built-in, language-level constructs. Instead, this is all implemented as libraries,
39 | written in a very straightforward way. In fact, we'll write most of that code
40 | ourselves over the course of this short book.
41 |
42 | Haskell is not the only language to have such a construct. For example, Scala
43 | has a similar `Option` type and Swift has `Optional` with various built-in
44 | syntax elements to make its usage more convenient. Many of the ideas implemented
45 | in these languages were lifted directly from Haskell. If you happen to use one
46 | of them, it can be good to learn where the ideas originated.
47 |
48 | ## Required Experience
49 |
50 | I'll assume no prior Haskell experience. I expect that those reading this book
51 | will have programmed in other, more traditional languages, but I'll also ask
52 | that you *actively combat* your prior programming experience.
53 |
54 | For example, you're going to see code like this:
55 |
56 | ```haskell
57 | countEvens = length . filter even
58 | ```
59 |
60 | This is a function definition written in an entirely different style than you
61 | may be used to. Even so, I'll bet you can guess what it does, and even get close
62 | to how it does it: `filter even` probably takes a list and filters it for only
63 | even elements. `length` probably takes a list and returns the number of elements
64 | it contains.
65 |
66 | Given those fairly obvious facts, you might guess that putting two things
67 | together with `(.)` must mean you do one and then give the result to the other.
68 | That makes this expression a function that must take a list and return the
69 | number of even elements it contains. Without mentioning any actual argument, we can
70 | directly assign this function the name `countEvens`. There's no need in Haskell
71 | to say that count-evens *of some x* is to take the length after filtering for
72 | the even values *of that x*. We can state directly that count-evens is taking
73 | the length after filtering for evens.
74 |
75 | This is a relatively contrived example, but it's an indication of the confusion
76 | that can happen at any level: if your first reaction is "such weird syntax! What
77 | is this crazy dot thing!?", you're going to have a bad time. Instead, try to
78 | internalize the parts that make sense while getting comfortable with *not*
79 | knowing the parts that don't. As you learn more, the various bits will tie
80 | together in ways you might not expect.
81 |
82 | ## Structure
83 |
84 | We'll spend this entire book focused on a single *type constructor* called
85 | `Maybe`. We'll start by quickly covering the basics of Haskell, but only far enough
86 | that we can see the opportunity for such a type and can't help but invent it
87 | ourselves. With that type defined, we'll quickly see that it's cumbersome to use.
88 | This is because Haskell has taken an inherently cumbersome concept and put it
89 | right in front of us by naming it, and by requiring we deal with it at every step.
90 |
91 | From there, we'll explore three *type classes* whose presence will make our
92 | lives far simpler. We'll see that `Maybe` has all the properties
93 | required to call it a *functor*, an *applicative functor*, and even a *monad*.
94 | These terms may sound scary, but we'll go through them slowly, each concept
95 | building on the one before. These three *interfaces* are crucial to how I/O is handled
96 | in a purely functional language such as Haskell. Understanding them will open
97 | your eyes to a whole new world of abstractions and demystify some notoriously opaque
98 | topics.
99 |
100 | Finally, with a firm grasp on how these concepts operate in the context of
101 | `Maybe`, we'll discuss other types that share these qualities. This is to
102 | reinforce the fact that these ideas are *abstractions*. They can be applied to
103 | any type that meets certain criteria. Ideas like *functor* and *monad* are not
104 | limited to, or specifically tied to, the concept of partial functions or nullable values. They
105 | apply much more broadly to things like lists, trees, exceptions, and program evaluation.
106 |
107 | ## What This Book is Not
108 |
109 | I don't intend to teach you Haskell. Rather, I want to show you *barely enough*
110 | Haskell that I can wade into some more interesting topics. I want to show how this
111 | `Maybe` data type can add safety to your code base while remaining convenient,
112 | expressive, and powerful. My hope is to show that Haskell and its "academic"
113 | ideas are not limited to PhD thesis papers. These ideas can result directly in
114 | cleaner, more maintainable code that solves practical problems.
115 |
116 | I won't describe how to set up a Haskell programming environment, show you how
117 | to write and run complete Haskell programs, or dive deeply into every language
118 | construct that we'll encounter. If you are interested in going further and actually
119 | learning Haskell (and I hope you are!), then I recommend following Chris Allen's
120 | great [learning path][learnhaskell].
121 |
122 | [learnhaskell]: https://github.com/bitemyapp/learnhaskell
123 |
124 | Finally, a word of general advice before you get started:
125 |
126 | The type system is not your enemy. It's your friend. It doesn't slow you down;
127 | it keeps you honest. Keep an open mind. Haskell is simpler than you think.
128 | Monads are not some mystical burrito. They're a simple abstraction that, when
129 | applied to a variety of problems, can lead to elegant solutions. Don't get
130 | bogged down in what you don't understand. Instead, dig deeper into what you do.
131 | And above all, take your time.
132 |
--------------------------------------------------------------------------------
/book/monad/bind.md:
--------------------------------------------------------------------------------
1 | ## Bind
2 |
3 | If you haven't guessed it, Haskell does have exactly this function. Its name is
4 | *bind* and it's defined as part of the `Monad` type class. Here is its type
5 | signature:
6 |
7 | ```haskell
8 | (>>=) :: m a -> (a -> m b) -> m b
9 | --
10 | -- where m is the type you're saying is a Monad (e.g. Maybe)
11 | --
12 | ```
13 |
14 | Again, you can see that `andThen` has the correct signature:
15 |
16 | ```haskell
17 | -- m a (a -> m b) -> m b
18 | andThen :: Maybe a -> (a -> Maybe b) -> Maybe b
19 | ```
20 |
21 | ## Chaining
22 |
23 | `(>>=)` is defined as an operator because it's meant to be used infix. It's also
24 | given an appropriate fixity so it can be chained together intuitively. This is
25 | why I chose the name `andThen` for my fictitious version: it can sometimes help
26 | to read `x >>= y >>= z` as *x and-then y and-then z*. To see this in action,
27 | let's walk through another example.
28 |
29 | Suppose we are working on a system with the following functions for dealing with
30 | users' addresses and their zip codes:
31 |
32 | ```haskell
33 | -- Returns Maybe because the user may not exist
34 | findUser :: UserId -> Maybe User
35 | findUser = undefined
36 |
37 | -- Returns Maybe because Users aren't required to have an address on file
38 | userZip :: User -> Maybe ZipCode
39 | userZip = undefined
40 | ```
41 |
42 | Let's also say we have a function to calculate shipping costs by zip code. It
43 | employs `Maybe` to handle invalid zip codes:
44 |
45 | ```haskell
46 | shippingCost :: ZipCode -> Maybe Cost
47 | shippingCost = undefined
48 | ```
49 |
50 | We could naively calculate the shipping cost for some user given their Id:
51 |
52 | ```haskell
53 | findUserShippingCost :: UserId -> Maybe Cost
54 | findUserShippingCost uid =
55 | case findUser uid of
56 | Just u -> case userZip u of
57 | Just z -> case shippingCost z of
58 | Just c -> Just c
59 |
60 | -- User has an invalid zip code
61 | Nothing -> Nothing
62 |
63 | -- Use has no address
64 | Nothing -> Nothing
65 |
66 | -- User not found
67 | Nothing -> Nothing
68 | ```
69 |
70 | This code is offensively ugly, but it's the sort of code I write every day in
71 | Ruby. We might hide it behind three-line methods each holding one level of
72 | conditional, but it's there.
73 |
74 | How does this code look with `(>>=)`?
75 |
76 | ```haskell
77 | findUserShippingCost :: UserId -> Maybe Cost
78 | findUserShippingCost uid = findUser uid >>= userZip >>= shippingCost
79 | ```
80 |
81 | You have to admit, that's quite nice. Hopefully even more so when you look back
82 | at the definition for `andThen` to see that that's all it took to clean up this
83 | boilerplate.
84 |
--------------------------------------------------------------------------------
/book/monad/do.md:
--------------------------------------------------------------------------------
1 | ## Do Notation
2 |
3 | There's one more topic I'd like to mention related to monads: *do-notation*.
4 |
5 | This bit of syntactic sugar is provided by Haskell for any of its `Monad`s. The
6 | reason is to allow functional Haskell code to read like imperative code when
7 | building compound expressions using `Monad`. This is valuable because monadic
8 | expressions, especially those representing interactions with the outside world,
9 | are often read best as a series of imperative steps:
10 |
11 | ```haskell
12 | f = do
13 | x <- something
14 | y <- anotherThing
15 | z <- combineThings x y
16 |
17 | finalizeThing z
18 | ```
19 |
20 | That said, this sugar is available for any `Monad` and so we can use it for
21 | `Maybe` as well. We can use `Maybe` as an example for seeing how *do-notation*
22 | works. Then, if and when you come across some `IO` expressions using
23 | *do-notation*, you won't be as surprised or confused.
24 |
25 | De-sugaring *do-notation* is a straightforward process followed out during
26 | Haskell compilation. It can be understood best by doing it manually. Let's start
27 | with our end result from the last example. We'll translate this code
28 | step by step into the equivalent *do-notation* form, then follow the same
29 | process backward, as the compiler would do if we had written it that way in the
30 | first place.
31 |
32 | ```haskell
33 | findUserShippingCost :: UserId -> Maybe Cost
34 | findUserShippingCost uid = findUser uid >>= userZip >>= shippingCost
35 | ```
36 |
37 | First, let's add some arbitrary line breaks so the eventual formatting aligns
38 | with what someone might write by hand:
39 |
40 | ```haskell
41 | findUserShippingCost :: UserId -> Maybe Cost
42 | findUserShippingCost uid =
43 | findUser uid >>=
44 | userZip >>=
45 |
46 | shippingCost
47 | ```
48 |
49 | Next, let's name the arguments to each expression via anonymous functions,
50 | rather than relying on partial application and their curried nature:
51 |
52 | ```haskell
53 | findUserShippingCost :: UserId -> Maybe Cost
54 | findUserShippingCost uid =
55 | findUser uid >>= \u ->
56 | userZip u >>= \z ->
57 |
58 | shippingCost z
59 | ```
60 |
61 | Next, we'll take each lambda and translate it into a *binding*, which looks a
62 | bit like variable assignment and uses `(<-)`. You can read `x <- y` as "x from
63 | y":
64 |
65 | ```haskell
66 | findUserShippingCost :: UserId -> Maybe Cost
67 | findUserShippingCost uid =
68 | u <- findUser uid
69 | z <- userZip u
70 |
71 | shippingCost z
72 | ```
73 |
74 | Finally, we prefix the series of "statements" with `do`:
75 |
76 | ```haskell
77 | findUserShippingCost :: UserId -> Maybe Cost
78 | findUserShippingCost uid = do
79 | u <- findUser uid
80 | z <- userZip u
81 |
82 | shippingCost z
83 | ```
84 |
85 | Et voilà, you have the equivalent *do-notation* version of our function. When
86 | the compiler sees code written like this, it follows (mostly) the same process
87 | we did, but in reverse:
88 |
89 | Remove the `do` keyword:
90 |
91 | ```haskell
92 | findUserShippingCost :: UserId -> Maybe Cost
93 | findUserShippingCost uid =
94 | u <- findUser uid
95 | z <- userZip u
96 |
97 | shippingCost z
98 | ```
99 |
100 | Translate each binding into a version using `(>>=)` and lambdas:
101 |
102 | ```haskell
103 | findUserShippingCost :: UserId -> Maybe Cost
104 | findUserShippingCost uid =
105 | findUser uid >>= \u ->
106 | userZip u >>= \z ->
107 |
108 | shippingCost z
109 | ```
110 |
111 | The compiler can stop here as all remaining steps are stylistic changes only. To
112 | get back to our exact original expression, we only need to
113 | *eta-reduce*[^eta-reduce] the lambdas:
114 |
115 | ```haskell
116 | findUserShippingCost :: UserId -> Maybe Cost
117 | findUserShippingCost uid =
118 | findUser uid >>=
119 | userZip >>=
120 |
121 | shippingCost
122 | ```
123 |
124 | And remove our arbitrary line breaks:
125 |
126 |
127 | ```haskell
128 | findUserShippingCost :: UserId -> Maybe Cost
129 | findUserShippingCost uid = findUser uid >>= userZip >>= shippingCost
130 | ```
131 |
132 | [^eta-reduce]: The process of simplifying `\x -> f x` to the equivalent form `f`.
133 |
--------------------------------------------------------------------------------
/book/monad/intro.md:
--------------------------------------------------------------------------------
1 | So far, we've seen that as `Maybe` makes our code safer, it also makes it less
2 | convenient. By making potential non-presence explicit, we now need to correctly
3 | account for it at every step. We addressed a number of scenarios by using `fmap`
4 | to "upgrade" a system full of normal functions (free of any `nil`-checks) into
5 | one that can take and pass along `Maybe` values. When confronted with a new
6 | scenario that could not be handled by `fmap` alone, we discovered a new function
7 | `(<*>)` which helped ease our pain again. This chapter is about addressing a
8 | third scenario, one that `fmap` and even `(<*>)` cannot solve: dependent
9 | computations.
10 |
11 | Let's throw a monkey wrench into our `getParam` example from earlier. This time,
12 | let's say we're accepting logins by either username or email. The user can say
13 | which method they're using by passing a `type` param specifying "username" or
14 | "email".
15 |
16 | *Note*: this whole thing is wildly insecure, but bear with me.
17 |
18 | Again, all of this is fraught with `Maybe`-ness and again, writing it with
19 | straight-line `case` matches can get very tedious:
20 |
21 | ```haskell
22 | loginUser :: Params -> Maybe User
23 | loginUser params = case getParam "type" of
24 | Just t -> case t of
25 | "username" -> case getParam "username" of
26 | Just u -> findUserByUserName u
27 | Nothing -> Nothing
28 | "email" -> case getParam "email" of
29 | Just e -> findUserByEmail e
30 | Nothing -> Nothing
31 | _ -> Nothing
32 | Nothing -> Nothing
33 | ```
34 |
35 | Yikes.
36 |
--------------------------------------------------------------------------------
/book/monad/power.md:
--------------------------------------------------------------------------------
1 | ## More Power
2 |
3 | We can't clean this up with `(<*>)` because each individual part of an
4 | `Applicative` expression doesn't have access to the results from any other
5 | part's evaluation. What does that mean? If we look at the `Applicative`
6 | expression from before:
7 |
8 | ```haskell
9 | User <$> getParam "name" params <*> getParam "email" params
10 | ```
11 |
12 | Here, the two results from `getParam "name"` and `getParam "email"` (either of
13 | which could be present or not) are passed together to `User`. If they're both
14 | present we get a `Just User`, otherwise `Nothing`. Within the `getParam "email"`
15 | expression, you can't reference the (potential) result of `getParam "name"`.
16 |
17 | We need that ability to solve our current conundrum because we need to check the
18 | value of the "type" param to know what to do next. We need... *monads*.
19 |
20 | ## And Then?
21 |
22 | Let's start with a minor refactor. We'll pull out a `loginByType` function:
23 |
24 | ```haskell
25 | loginUser :: Params -> Maybe User
26 | loginUser params = case getParam "type" params of
27 | Just t -> loginByType params t
28 | Nothing -> Nothing
29 |
30 | loginByType :: Params -> String -> Maybe User
31 | loginByType params "username" = case getParam "username" params of
32 | Just u -> findUserByUserName u
33 | Nothing -> Nothing
34 |
35 | loginByType params "email" = case getParam "email" params of
36 | Just e -> findUserByEmail e
37 | Nothing -> Nothing
38 |
39 | loginByType _ _ = Nothing
40 | ```
41 |
42 | Things seem to be following a pattern now: we have some value that might not be
43 | present and some function that needs the (fully present) value, does some other
44 | computation with it, but may itself fail.
45 |
46 | Let's abstract this concern into a new function called `andThen`:
47 |
48 |
49 | ```haskell
50 | andThen :: Maybe a -> (a -> Maybe b) -> Maybe b
51 | andThen (Just x) f = f x
52 | andThen _ _ = Nothing
53 | ```
54 |
55 | We'll use the function infix via backticks for readability:
56 |
57 | ```haskell
58 | loginUser :: Params -> Maybe User
59 | loginUser params =
60 | getParam "type" params `andThen` loginByType params
61 |
62 | loginByType :: Params -> String -> Maybe User
63 | loginByType params "username" =
64 | getParam "username" params `andThen` findUserByUserName
65 |
66 | loginByType params "email" =
67 | getParam "email" params `andThen` findUserByEmail
68 |
69 | -- Still needed in case we get an invalid type
70 | loginByType _ _ = Nothing
71 | ```
72 |
73 | This cleans things up nicely. The concern of "passing along the `Maybe`" is
74 | completely abstracted away behind `andThen` and we're free to describe the
75 | nature of *our* computation. If only Haskell had such a function...
76 |
--------------------------------------------------------------------------------
/book/monad/wrapping-up.md:
--------------------------------------------------------------------------------
1 | ## Wrapping Up
2 |
3 | And thus ends our discussion of monads. This also ends our discussion of
4 | `Maybe`. You've now seen the type itself and three of Haskell's most important
5 | abstractions, which make its use convenient while still remaining explicit and
6 | safe. To highlight the point that these abstractions (`Functor`, `Applicative`,
7 | and `Monad`) are *interfaces* shared by many types, the next and final section
8 | will briefly show a few other useful types that also have these three
9 | interfaces.
10 |
--------------------------------------------------------------------------------
/book/other-types/either.md:
--------------------------------------------------------------------------------
1 | ## Either
2 |
3 | Haskell has another type to help with computations that may fail:
4 |
5 | ```haskell
6 | data Either a b = Left a | Right b
7 | ```
8 |
9 | Traditionally, the `Right` constructor is used for a successful result (what a
10 | function would have returned normally) and `Left` is used in the failure case. The
11 | value of type `a` given to the `Left` constructor is meant to hold information
12 | about the failure: why did it fail? This is only a convention, but it's a
13 | strong one that we'll use throughout this chapter. To see one formalization of
14 | this convention, take a look at [Control.Monad.Except][except]. It can appear
15 | intimidating because it is so generalized, but [Example 1][example] should look
16 | a lot like what I'm about to walk through here.
17 |
18 | [except]: http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html
19 | [example]: http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html#g:3
20 |
21 | With `Maybe a`, the `a` was the value and `Maybe` was the context. Therefore, we
22 | made instances of `Functor`, `Applicative`, and `Monad` for `Maybe` (not `Maybe
23 | a`). With `Either` as we've written it above, `b` is the value and `Either a` is
24 | the context, therefore Haskell has instances of `Functor`, `Applicative`, and
25 | `Monad` for `Either a` (not `Either a b`).
26 |
27 | This use of `Left a` to represent failure with error information of type `a` can
28 | get confusing when we start looking at functions like `fmap`. Here's why: the
29 | generalized type of `fmap` talks about `f a` and I said our instance would be
30 | for `Either a` making that `Either a a`, but they aren't the same `a`!
31 |
32 | For this reason, we can imagine an alternate definition of `Either` that uses
33 | different variables. This is perfectly reasonable since the variables are chosen
34 | arbitrarily anyway:
35 |
36 | ```haskell
37 | data Either e a = Left e | Right a
38 | ```
39 |
40 | When we get to `fmap` (and others), things are clearer:
41 |
42 | ```haskell
43 | -- (a -> b) f a -> f b
44 | fmap :: (a -> b) -> Either e a -> Either e b
45 | ```
46 |
47 | ### ParserError
48 |
49 | As an example, consider some kind of parser. If parsing fails, it would be nice
50 | to include some information about what triggered the failure. To accomplish
51 | this, we first define a type to represent this information. For our purposes,
52 | it's the line and column where something unexpected appeared, but it could be
53 | much richer than that including what was expected and what was seen instead:
54 |
55 | ```haskell
56 | data ParserError = ParserError Int Int
57 | ```
58 |
59 | From this, we can make a domain-specific type alias built on top of `Either`. We
60 | can say a value that we parse may fail. If it does,
61 | error information will appear in a `Left`-constructed result. If it succeeds, we'll get the
62 | `a` we originally wanted in a `Right`-constructed result.
63 |
64 | ```haskell
65 | -- Either e a = Left e | Right a
66 | type Parsed a = Either ParserError a -- = Left ParserError | Right a
67 | ```
68 |
69 | Finally, we can give an informative type to functions that may produce such results:
70 |
71 | ```haskell
72 | parseJSON :: String -> Parsed JSON
73 | parseJSON = undefined
74 | ```
75 |
76 | This informs callers of `parseJSON` that it may fail and, if it does, the
77 | invalid character and line can be found:
78 |
79 | ```haskell
80 | jsonString = "..."
81 |
82 | case parseJSON jsonString of
83 | Right json -> -- do something with json
84 | Left (ParserError ln col) -> -- do something with the error information
85 | ```
86 |
87 | ### Functor
88 |
89 | You may have noticed that we've reached the same conundrum as with `Maybe`: often,
90 | the best thing to do if we encounter a `Left` result is to pass it along to our
91 | own callers. Wouldn't it be nice if we could take some JSON-manipulating
92 | function and apply it directly to something that we parse? Wouldn't it be nice if the
93 | "pass along the errors" concern were handled separately?
94 |
95 | ```haskell
96 | -- Replace the value at the given key with the new value
97 | replace :: Key -> Value -> JSON -> JSON
98 | replace = undefined
99 |
100 | --
101 | -- This is a type error!
102 | --
103 | -- replace "admin" False is (JSON -> JSON), but parseJSON returns (Parsed JSON)
104 | --
105 | replace "admin" False (parseJSON jsonString)
106 | ```
107 |
108 | `Parsed a` is a value in some context, like `Maybe a`. This time, rather than
109 | only present-or-non-present, the context is richer. It represents
110 | present-or-non-present-with-error. Can you think of how this context should be
111 | accounted for under an operation like `fmap`?
112 |
113 | ```haskell
114 | -- (a -> b) -> f a -> f b
115 | -- (a -> b) -> Either e a -> Either e b
116 | fmap :: (a -> b) -> Parsed a -> Parsed b
117 | fmap f (Right v) = Right (f v)
118 | fmap _ (Left e) = Left e
119 | ```
120 |
121 | If the value is there, we apply the given function to it. If it's not, we pass
122 | along the error. Now we can do something like this:
123 |
124 | ```haskell
125 | fmap (replace "admin" False) (parseJSON jsonString)
126 | ```
127 |
128 | If the incoming string is valid, we get a successful `Parsed JSON` result with
129 | the `"admin"` key replaced by `False`. Otherwise, we get an unsuccessful `Parsed
130 | JSON` result with the original error message still available.
131 |
132 | Knowing that `Control.Applicative` provides `(<$>)` as an infix synonym for
133 | `fmap`, we could also use that to make this read a bit better:
134 |
135 | ```haskell
136 | replace "admin" False <$> parseJSON jsonString
137 | ```
138 |
139 | Speaking of `Applicative`...
140 |
141 | ### Applicative
142 |
143 | It would also be nice if we could take two potentially failed results and pass
144 | them as arguments to some function that takes normal values. If any result
145 | fails, the overall result is also a failure. If all are successful, we get a
146 | successful overall result. This sounds a lot like what we did with `Maybe`. The
147 | only difference is that we're doing it for a different kind of context.
148 |
149 | ```haskell
150 | -- Given two json objects, merge them into one
151 | merge :: JSON -> JSON -> JSON
152 | merge = undefined
153 |
154 | jsonString1 = "..."
155 |
156 | jsonString2 = "..."
157 |
158 | merge <$> parseJSON jsonString1 <*> parseJSON jsonString2
159 | ```
160 |
161 | `merge <$> parseJSON jsonString1` gives us a `Parsed (JSON -> JSON)`. (If this
162 | doesn't make sense, glance back at the examples in the Applicative chapter.)
163 | What we have is a *function* in a `Parsed` context. `parseJSON jsonString2`
164 | gives us a `Parsed JSON`, a *value* in a `Parsed` context. The job of `(<*>)` is
165 | to apply the `Parsed` function to the `Parsed` value and produce a `Parsed`
166 | result.
167 |
168 | Defining `(<*>)` starts out all right: if both values are present we'll get the
169 | result of applying the function wrapped up again in `Right`. If the second
170 | value's not there, that error is preserved as a new `Left` value:
171 |
172 | ```haskell
173 | -- f (a -> b) -> f a -> f b
174 | -- Either e (a -> b) -> Either e a -> Either e b
175 | (<*>) :: Parsed (a -> b) -> Parsed a -> Parsed b
176 | Right f <*> Right x = Right (f x)
177 | Right _ <*> Left e = Left e
178 | ```
179 |
180 | Astute readers may notice that we could reduce this to one pattern by using
181 | `fmap`. This is left as an exercise.
182 |
183 | What about the case where the first argument is `Left`? At first this seems
184 | trivial: there's no use inspecting the second value because we know something has
185 | already failed, so let's pass that along, right? Well, what if the second value
186 | was also an error? Which error should we keep? Either way we discard one of
187 | them. Any potential loss of information should be met with pause.
188 |
189 | It [turns out][gist], it doesn't matter, at least not as far as the
190 | Applicative Laws are concerned. If choosing one over the other had violated any
191 | of the laws, we would have had our answer. Beyond those, we don't know how this
192 | instance will eventually be used by end-users and we can't say which is the
193 | "right" choice standing here now.
194 |
195 | [gist]: https://gist.github.com/pbrisbin/b9a0c142d6ccdb8580a5
196 |
197 | Given that the choice is arbitrary, I present the actual definition from
198 | `Control.Applicative`:
199 |
200 | ```haskell
201 | Left e <*> _ = Left e
202 | ```
203 |
204 | ### Monad
205 |
206 | When thinking through the `Monad` instance for our `Parsed` type, we don't have
207 | the same issue of deciding which error to propagate. Remember that the extra
208 | power offered by monads is that computations can depend on the results of prior
209 | computations. When the context involved represents failure (which may not always
210 | be the case!), any single failing computation must trigger the omission of all
211 | subsequent computations (since they could be depending on some result that's not
212 | there). This means we only need to propagate that first failure.
213 |
214 | Let's say we're interacting with a JSON web service for getting blog post
215 | content. The responses include the body of the post as a string of HTML:
216 |
217 | ```
218 | {
219 | "title": "A sweet blog post",
220 | "body": "The post content...
"
221 | }
222 | ```
223 |
224 | Parsing JSON like this includes parsing the value at the `"body"` key into a
225 | structured `HTML` data type. For this, we can re-use our `Parsed` type:
226 |
227 | ```haskell
228 | parseHTML :: Value -> Parsed HTML
229 | parseHTML = undefined
230 | ```
231 |
232 | We can directly parse a `String` of JSON into the `HTML` present at one of its
233 | keys by binding the two parses together with `(>>=)`:
234 |
235 | ```haskell
236 | -- Grab the value at the given key
237 | at :: Key -> JSON -> Value
238 | at = undefined
239 |
240 | parseBody :: String -> Parsed HTML
241 | parseBody jsonString = parseJSON jsonString >>= parseHTML . at "body"
242 | ```
243 |
244 | First, `parseJSON jsonString` gives us a `Parsed JSON`. This is the `m a` in
245 | `(>>=)`'s type signature. Then we use `(.)` to compose a function that gets the
246 | value at the `"body"` key and passes it to `parseHTML`. The type of this
247 | function is `(JSON -> Parsed HTML)`, which aligns with the `(a -> m b)` of
248 | `(>>=)`'s second argument. Knowing that `(>>=)` will return `m b`, we can see
249 | that that's the `Parsed HTML` we're after.
250 |
251 | If both parses succeed, we get a `Right`-constructed value containing the `HTML`
252 | we want. If either parse fails, we get a `Left`-constructed value containing the
253 | `ParserError` from whichever failed.
254 |
255 | Allowing such a readable expression (*parse JSON and then parse HTML at body*),
256 | requires the following straightforward implementation for `(>>=)`:
257 |
258 | ```haskell
259 | -- m a -> (a -> m b) -> m b
260 | -- Either e a -> (a -> Either e b) -> Either e b
261 | (>>=) :: Parsed a -> (a -> Parsed b) -> Parsed b
262 | Right v >>= f = f v
263 | Left e >>= _ = Left e
264 | ```
265 |
266 | Armed with instances for `Functor`, `Applicative`, and `Monad` for both `Maybe`
267 | and `Either e`, we can use the same set of functions (those with `Functor f`,
268 | `Applicative f` or `Monad m` in their class constraints) and apply them to a
269 | variety of functions that may fail (with or without useful error information).
270 |
271 | This is a great way to reduce a project's maintenance burden. If you start with
272 | functions returning `Maybe` values but use generalized functions for (e.g.) any
273 | `Monad m`, you can later upgrade to a fully fledged `Error` type based on
274 | `Either` without having to change most of the code base.
275 |
--------------------------------------------------------------------------------
/book/other-types/intro.md:
--------------------------------------------------------------------------------
1 | The three abstractions you've seen all require a certain kind of value.
2 | Specifically, a value with some other bit of information, often referred to as
3 | its *context*. In the case of a type like `Maybe a`, the `a` represents the
4 | value itself and `Maybe` represents the fact that it may or may not be present.
5 | This potential non-presence is that other bit of information, its context.
6 |
7 | Haskell's type system is unique in that it lets us speak specifically about this
8 | other bit of information without involving the value itself. In fact, when
9 | defining instances for `Functor`, `Applicative` and `Monad`, we were defining an
10 | instance for `Maybe`, not for `Maybe a`. When we define these instances we're
11 | not defining how `Maybe a`, a value in some context, behaves under certain
12 | computations, we're actually defining how `Maybe`, the context itself, behaves
13 | under certain computations.
14 |
15 | This kind of separation of concerns is difficult to understand when you're only
16 | accustomed to languages that don't allow for it. I believe it's why topics like
17 | monads seem so opaque to those unfamiliar with a type system like this. To
18 | strengthen the point that what we're really talking about are behaviors and
19 | contexts, not any one specific *thing*, this chapter will explore types that
20 | represent other kinds of contexts and show how they behave under all the same
21 | computations we saw for `Maybe`.
22 |
--------------------------------------------------------------------------------
/book/other-types/io/intro.md:
--------------------------------------------------------------------------------
1 | ## IO
2 |
3 | So far, we've seen three types: `Maybe a`, `Either e a`, and `[a]`. These types
4 | all represent a value with some other bit of information: a *context*. If `a` is
5 | the `User` you're trying to find, the `Maybe` says if she was actually found. If
6 | the `a` is the `JSON` you're attempting to parse, the `Either e` holds
7 | information about the error when the parse fails. If `a` is a number, then `[]`
8 | tells you it is actually many numbers at once, and how many.
9 |
10 | For all these types, we've seen the behaviors that allow us to add them to the
11 | `Functor`, `Applicative`, and `Monad` type classes. These behaviors obey certain
12 | laws which allow us to reason about what will happen when we use functions like
13 | `fmap` or `(>>=)`. In addition to this, we can also reach in and manually
14 | resolve the context. We can define a `fromMaybe` function to reduce a `Maybe a`
15 | to an `a` by providing a default value for the `Nothing` case. We can do a
16 | similar thing for `Either e a` with the `either` function. Given a `[a]` we can
17 | resolve it to an `a` by selecting one at a given index (taking care to handle
18 | the empty list).
19 |
20 | The `IO` type, so important to Haskell, is exactly like the three types you've
21 | seen so far in that it represents a value in some context. With a value of type
22 | `IO a`, the `a` is the thing you want and the `IO` means some input or output
23 | will be performed in the real word as part of producing that `a`. The difference
24 | is that the only way we can combine `IO` values is through their `Functor`,
25 | `Applicative`, and `Monad` interfaces. In fact, it's really only through its
26 | `Monad` interface since the `Applicative` and `Functor` instances are defined in
27 | terms of it. We can't ourselves resolve an `IO a` to an `a`. This has many
28 | ramifications in how programs must be constructed.
29 |
30 | ### Effects in a pure world
31 |
32 | One question I get asked a lot is, "how is it that Haskell, a *pure* functional
33 | programming language, can actually do anything? How does it create or read
34 | files? How does it print to the terminal? How does it serve web requests?"
35 |
36 | The short answer is, it doesn't. To show this, let's start with the following
37 | Ruby program:
38 |
39 | ```ruby
40 | def main
41 | print "give me a word: "
42 |
43 | x = gets
44 |
45 | puts x
46 | end
47 | ```
48 |
49 | When you run this program with the Ruby interpreter, does anything happen? It
50 | depends on your definition of *happen*. Certainly, no I/O will happen, but
51 | that's not *nothing*. Objects will be instantiated, and a method has been
52 | defined. By defining this method, you've constructed a blue-print for some
53 | actions to be performed, but then neglected to perform them.
54 |
55 | Ruby expects (and allows) you to invoke effecting methods like `main` whenever
56 | and wherever you want. If you want the above program to do something, you need
57 | to call `main` at the bottom. This is a blessing and a curse. While the
58 | flexibility is appreciated, it's a constant source of bugs and makes methods and
59 | objects impossible to reason about without looking at their implementations. A
60 | method may look "pure", but internally it might access a database, pull from an
61 | external source of randomness, or fire nuclear missiles. Haskell doesn't work
62 | like that.
63 |
64 | Here's a translation of the Ruby program into Haskell:
65 |
66 | ```haskell
67 | main :: IO ()
68 | main = do
69 | putStr "give me a word: "
70 |
71 | x <- getLine
72 |
73 | putStrLn x
74 | ```
75 |
76 | Much like the Ruby example, this code doesn't *do* anything. It defines a
77 | function `main` that states what should happen when it's executed. It does not
78 | execute anything itself. Unlike Ruby, Haskell does not expect or allow you to
79 | call `main` yourself. The Haskell runtime will handle that and perform whatever
80 | I/O is required for you. This is how I/O happens in a pure language: you define
81 | the blue-print, a *pure* value that says *how* to perform any I/O, then you give
82 | that to a separate runtime, which is in charge of actually performing it.
83 |
--------------------------------------------------------------------------------
/book/other-types/io/main.md:
--------------------------------------------------------------------------------
1 | ### Typed puzzles
2 |
3 | Starting with the type of `main`, we immediately see something worth explaining:
4 |
5 | ```haskell
6 | main :: IO ()
7 | ```
8 |
9 | The type of `main` is pronounced *IO void*. `()` itself is a type defined with a
10 | single constructor. It can also be thought of as an empty tuple:
11 |
12 | ```haskell
13 | data () = ()
14 | ```
15 |
16 | It's used to stand in when a computation affects the *context*, but produces no
17 | useful *result*. It's not specific to `IO` (or monads for that matter). For
18 | example, if you were chaining a series of `Maybe` values together using `(>>=)`
19 | and under some condition you wanted to manually trigger an overall `Nothing`
20 | result, you could insert a `Nothing` of type `Maybe ()` into the expression.
21 |
22 | This is exactly how the [guard][] function works. When specialized to `Maybe`,
23 | its definition is:
24 |
25 | ```haskell
26 | guard :: Bool -> Maybe ()
27 | guard True = Just ()
28 | guard False = Nothing
29 | ```
30 |
31 | It is used like this:
32 |
33 | ```haskell
34 | findAdmin :: UserId -> Maybe User
35 | findAdmin uid = do
36 | user <- findUser uid
37 |
38 | guard (isAdmin user)
39 |
40 | return user
41 | ```
42 |
43 | [guard]: http://hackage.haskell.org/package/base-4.7.0.2/docs/Control-Monad.html#v:guard
44 |
45 | If you're having trouble seeing why this expression works, start by de-sugaring
46 | from *do-notation* to the equivalent expression using `(>>=)`, then use the
47 | `Maybe`-specific definitions of `(>>=)`, `return`, and `guard` to reduce the
48 | expression when an admin is found, a non-admin is found, or no user is found.
49 |
50 | Next, let's look at the individual pieces we'll be combining into `main`:
51 |
52 | ```haskell
53 | putStr :: String -> IO ()
54 |
55 | putStrLn :: String -> IO ()
56 | ```
57 |
58 | `putStr` also doesn't have any useful result so it uses `()`. It takes the given
59 | `String` and returns an action that *represents* printing that string, without a
60 | trailing newline, to the terminal. `putStrLn` is exactly the same, but includes
61 | a trailing newline.
62 |
63 | ```haskell
64 | getLine :: IO String
65 | ```
66 |
67 | `getLine` doesn't take any arguments and has type `IO String` which means an
68 | action that represents reading a line of input from the terminal. It requires
69 | `IO` and presents the read line as its result.
70 |
71 | Next, let's review the type of `(>>=)`:
72 |
73 | ```haskell
74 | (>>=) :: m a -> (a -> m b) -> m b
75 | ```
76 |
77 | In our case, `m` will always be `IO`, but `a` and `b` will be different each
78 | time we use `(>>=)`. The first combination we need is `putStr` and `getLine`.
79 | `putStr "..."` fits as `m a`, because its type is `IO ()`, but `getLine` does
80 | not have the type `() -> IO b` which is required for things to line up. There's
81 | another operator, built on top of `(>>=)`, designed to fix this problem:
82 |
83 | ```haskell
84 | (>>) :: m a -> m b -> m b
85 | ma >> mb = ma >>= \_ -> mb
86 | ```
87 |
88 | It turns its second argument into the right type for `(>>=)` by wrapping it in a
89 | lambda that accepts and ignores the `a` returned by the first action. With this,
90 | we can write our first combination:
91 |
92 | ```haskell
93 | main = putStr "..." >> getLine
94 | ```
95 |
96 | What is the type of this expression? If `(>>)` is `m a -> m b -> m b` and we've
97 | got `m a` as `IO ()` and `m b` as `IO String`. This combined expression must be
98 | `IO String`. It represents an action that, *when executed*, would print the
99 | given string to the terminal, then read in a line.
100 |
101 | Our next requirement is to put this action together with `putStrLn`. Our current
102 | expression has type `IO String` and `putStrLn` has type `String -> IO ()`. This
103 | lines up perfectly with `(>>=)` by taking `m` as `IO`, `a` as `String`, and `b`
104 | as `()`:
105 |
106 | ```haskell
107 | main = putStr "..." >> getLine >>= putStrLn
108 | ```
109 |
110 | This code is equivalent to the do-notation version I showed before. If you're
111 | not sure, try to manually convert between the two forms. The steps required were
112 | shown in the do-notation sub-section of the Monad chapter.
113 |
114 | Hopefully, this exercise has convinced you that while I/O in Haskell may appear
115 | confusing at first, things are quite a bit simpler:
116 |
117 | - Any function with an `IO` type *represents* an action to be performed
118 | - Actions are not executed, only combined into larger actions using `(>>=)`
119 | - The only way to get the runtime to execute an action is to assign it the
120 | special name `main`
121 |
122 | From these rules and the general requirement of type-safety, it emerges that any
123 | value of type `IO a` can only be called directly or indirectly from `main`.
124 |
--------------------------------------------------------------------------------
/book/other-types/io/more.md:
--------------------------------------------------------------------------------
1 | ### Learning more
2 |
3 | There are many resources online for learning about `Monad` and `IO` in Haskell.
4 | I recommend reading them all. Some are better than others and many get a bad rap
5 | for using some grandiose analogy that only makes sense to the author. Be mindful
6 | of this, but know that no single tutorial can give you a complete understanding
7 | because that requires looking at the same abstract thing from a variety of
8 | angles. Therefore, the best thing to do is read it all and form your own
9 | intuitions.
10 |
11 | If you're interested in the origins of monadic I/O in Haskell, I recommend
12 | [Tackling the Awkward Squad: monadic input/output, concurrency, exceptions, and
13 | foreign-language calls in Haskell][spj] by Simon Peyton Jones and [Comprehending
14 | Monads][wadler] by Philip Wadler.
15 |
16 | [spj]: http://research.microsoft.com/en-us/um/people/simonpj/papers/marktoberdorf/mark.pdf
17 | [wadler]: http://ncatlab.org/nlab/files/WadlerMonads.pdf
18 |
--------------------------------------------------------------------------------
/book/other-types/io/other-instances.md:
--------------------------------------------------------------------------------
1 | ### Other instances
2 |
3 | Unlike previous chapters, here I jumped right into `Monad`. This was because
4 | there's a natural flow from imperative code to monadic programming with
5 | do-notation, to the underlying expressions combined with `(>>=)`. As I
6 | mentioned, this is the only way to combine `IO` values. While `IO` does have
7 | instances for `Functor` and `Applicative`, the functions in these classes
8 | (`fmap` and `(<*>)`) are defined in terms of `return` and `(>>=)` from its
9 | `Monad` instance. For this reason, I won't be showing their definitions. That
10 | said, these instances are still useful. If your `IO` code doesn't require the
11 | full power of monads, it's better to use a weaker constraint. More general
12 | programs are better; weaker constraints on what kind of data your functions
13 | can work with makes them more generally useful.
14 |
15 | #### Functor
16 |
17 | `fmap`, when specialized to `IO`, has the following type:
18 |
19 | ```haskell
20 | fmap :: (a -> b) -> IO a -> IO b
21 | ```
22 |
23 | It takes a function and an `IO` action and returns another `IO` action, which
24 | represents applying that function to the *eventual* result returned by the
25 | first.
26 |
27 | It's common to see Haskell code like this:
28 |
29 | ```haskell
30 | readInUpper :: FilePath -> IO String
31 | readInUpper fp = do
32 | contents <- readFile fp
33 |
34 | return (map toUpper contents)
35 | ```
36 |
37 | All this code does is form a new action that applies a function to the eventual
38 | result of another. We can say this more concisely using `fmap`:
39 |
40 | ```haskell
41 | readInUpper :: FilePath -> IO String
42 | readInUpper fp = fmap (map toUpper) (readFile fp)
43 | ```
44 |
45 | As another example, we can use `fmap` with the Prelude function `lookup` to
46 | write a safer version of `getEnv` from the `System.Environment` module. `getEnv`
47 | has the nasty quality of raising an exception if the environment variable you're
48 | looking for isn't present. Hopefully this book has convinced you it's better to
49 | return a `Maybe` in this case. The `lookupEnv` function was eventually added to
50 | the module, but if you intend to support old versions, you'll need to define it
51 | yourself:
52 |
53 | ```haskell
54 | import System.Environment (getEnvironment)
55 |
56 | -- lookup :: Eq a => a -> [(a, b)] -> Maybe b
57 | --
58 | -- getEnvironment :: IO [(String, String)]
59 |
60 | lookupEnv :: String -> IO (Maybe String)
61 | lookupEnv v = fmap (lookup v) getEnvironment
62 | ```
63 |
64 | #### Applicative
65 |
66 | Imagine a library function for finding differences between two strings:
67 |
68 | ```haskell
69 | data Diff = Diff [Difference]
70 | data Difference = Added | Removed | Changed
71 |
72 | diff :: String -> String -> Diff
73 | diff = undefined
74 | ```
75 |
76 | How would we run this code on files from the file system? One way, using
77 | `Monad`, would look like this:
78 |
79 | ```haskell
80 | diffFiles :: FilePath -> FilePath -> IO Diff
81 | diffFiles fp1 fp2 = do
82 | s1 <- readFile fp1
83 | s2 <- readFile fp2
84 |
85 | return (diff s1 s2)
86 | ```
87 |
88 | Notice that the second `readFile` does not depend on the result of the first.
89 | Both `readFile` actions produce values that are combined *at once* using the
90 | pure function `diff`. We can make this lack of dependency explicit and bring the
91 | expression closer to what it would look like without `IO` values by using
92 | `Applicative`:
93 |
94 | ```haskell
95 | diffFiles :: FilePath -> FilePath -> IO Diff
96 | diffFiles fp1 fp2 = diff <$> readFile fp1 <*> readFile fp2
97 | ```
98 |
99 | As an exercise, try breaking down the types of the intermediate expressions
100 | here, like we did for `Maybe` in the Follow the Types sub-section of the
101 | Applicative chapter.
102 |
--------------------------------------------------------------------------------
/book/other-types/io/statements.md:
--------------------------------------------------------------------------------
1 | ### Statements and the curse of do-notation
2 |
3 | The Haskell function above used *do-notation*. I did this to highlight that the
4 | reason do-notation exists is for Haskell code to look like that equivalent,
5 | imperative Ruby, on which it was based. This fact has the unfortunate consequence
6 | of tricking new Haskell programmers into thinking that `putStr` (for example) is
7 | an imperative statement that actually puts the string to the screen when
8 | evaluated.
9 |
10 | In the Ruby code, each statement is implicitly combined with the next as the
11 | interpreter sees them. There is some initial global state, statements modify
12 | that global state, and the interpreter handles ensuring that subsequent
13 | statements see an updated global state from all those that came before. If Ruby
14 | used a semicolon instead of white space to delimit statements, we could almost
15 | think of `(;)` as an operator for combining statements and keeping track of the
16 | global state between them.
17 |
18 | In Haskell, there are no statements, only expressions. Every expression has a
19 | type and compound expressions must be combined in a type-safe way. In the case
20 | of `IO` expressions, they are combined with `(>>=)`. The semantic result is very
21 | similar to Ruby's statements. It's because of this that you may hear `(>>=)`
22 | referred to as a *programmable semicolon*. In truth, it's so much more than
23 | that. It's a first-class function that can be passed around, built on top of,
24 | and overloaded from type to type.
25 |
26 | To see how this works, let's build an equivalent definition for `main`, only
27 | this time no do-notation, only `(>>=)`.
28 |
--------------------------------------------------------------------------------
/book/other-types/list.md:
--------------------------------------------------------------------------------
1 | ## List
2 |
3 | At various points in the book, I relied on most programmers having an
4 | understanding of arrays and lists of elements to ease the learning curve up to
5 | `Maybe` and particularly `fmap`. In this chapter, I'll recap and expand on some
6 | of the things I've said before and then show that `[a]` is more than a list of
7 | elements over which we can map. It also has `Applicative` and `Monad` instances
8 | that make it a natural fit for certain problems.
9 |
10 | ### Tic-Tac-Toe and the Minimax algorithm
11 |
12 | For this chapter's example, I'm going to show portions of a program for playing
13 | Tic-Tac-Toe. The full program is too large to include, but portions of it are
14 | well-suited to using the `Applicative` and `Monad` instances for `[]`. The
15 | program uses an algorithm known as [minimax][] to choose the best move to make
16 | in a game of Tic-Tac-Toe.
17 |
18 | [minimax]: http://en.wikipedia.org/wiki/Minimax
19 |
20 | In short, the algorithm plays out all possible moves from the perspective of one
21 | player and chooses the one that maximizes their score and minimizes their
22 | opponent's, hence the name. Tic-Tac-Toe is a good game for exploring this
23 | algorithm because the possible choices are small enough that we can take the
24 | naive approach of enumerating all of them, then choosing the best.
25 |
26 | To model our Tic-Tac-Toe game, we'll need some data types:
27 |
28 | ```haskell
29 | -- A player is either Xs or Os
30 | data Player = X | O
31 |
32 | -- A square is either open, or taken by one of the players
33 | data Square = Open | Taken Player
34 |
35 | -- A row is top, middle, or bottom
36 | data Row = T | M | B
37 |
38 | -- A column is left, center, or right
39 | data Column = L | C | R
40 |
41 | -- A position is the combination of row and column
42 | type Position = (Row, Column)
43 |
44 | -- A space is the combination of position and square
45 | type Space = (Position, Square)
46 |
47 | -- Finally, the board is a list of spaces
48 | type Board = [Space]
49 | ```
50 |
51 | And some utility functions:
52 |
53 | ```haskell
54 | -- Is the game over?
55 | over :: Board -> Bool
56 | over = undefined
57 |
58 | -- The opponent for the given player
59 | opponent :: Player -> Player
60 | opponent = undefined
61 |
62 | -- Play a space for the player in the given board
63 | play :: Player -> Position -> Board -> Board
64 | play = undefined
65 | ```
66 |
67 | ### Applicative
68 |
69 | One of the things this program needs to do is generate a `Board` with all
70 | `Square`s `Open`. We could do this directly:
71 |
72 | ```haskell
73 | openBoard :: Board
74 | openBoard =
75 | [ ((T, L), Open), ((T, C), Open), ((T, R), Open)
76 | , ((M, L), Open), ((M, C), Open), ((M, R), Open)
77 | , ((B, L), Open), ((B, C), Open), ((B, R), Open)
78 | ]
79 | ```
80 |
81 | But that approach is tedious and error-prone. Another way to solve this problem
82 | is to create an `Open` square for all combinations of `Row`s and `Column`s. We
83 | can do exactly this with the `Applicative` instance for `[]`:
84 |
85 | ```haskell
86 | openSpace :: Row -> Column -> Space
87 | openSpace r c = ((r, c), Open)
88 |
89 | openBoard :: Board
90 | openBoard = openSpace <$> [T, M, B] <*> [L, C, R]
91 | ```
92 |
93 | Let's walk through the body of `openBoard` to see why it gives the result we
94 | need. First, `openSpace <$> [T, M, B]` maps the two-argument `openSpace` over
95 | the list `[T, M, B]`. This creates a list of partially applied functions. Each
96 | of these functions has been given a `Row` but still needs a `Column` to produce
97 | a full `Space`. We can show this as a list of lambdas taking a `Column` and
98 | building a `Space` with the `Row` it has already:
99 |
100 | ```haskell
101 | (<$>) :: (a -> b) -> f a -> f b
102 |
103 | -- a b
104 | openSpace :: Row -> (Column -> Space)
105 |
106 | -- f b
107 | openSpace <$> [T, M, B] :: [] (Column -> Space)
108 |
109 | openSpace <$> [T, M, B]
110 | -- => [ (\c -> ((T, c), Open))
111 | -- => , (\c -> ((M, c), Open))
112 | -- => , (\c -> ((B, c), Open))
113 | -- => ]
114 | ```
115 |
116 |
117 | Like the `Maybe` example from the `Applicative` chapter, we've created a
118 | function in a context. Here we have the function `(Column -> Space)` in the `[]`
119 | context: `[(Column -> Space)]`. Separating the type constructor from its
120 | argument and writing `[(Column -> Space)]` as `[] (Column -> Space)` shows how
121 | it matches the `f b` in `(<$>)`s type signature. How do we apply a function in a
122 | context to a value in a context? With `(<*>)`.
123 |
124 | Using `(<*>)` with lists means applying every function to every value:
125 |
126 | ```haskell
127 | openSpace <$> [T, M, B] <*> [L, C, R]
128 | -- => [ (\c -> ((T, c), Open)) L (first function applied to each value)
129 | -- => , (\c -> ((T, c), Open)) C
130 | -- => , (\c -> ((T, c), Open)) R
131 | -- => , (\c -> ((M, c), Open)) L (second function applied to each value)
132 | -- => , (\c -> ((M, c), Open)) C
133 | -- => , (\c -> ((M, c), Open)) R
134 | -- => , (\c -> ((B, c), Open)) L (third function applied to each value)
135 | -- => , (\c -> ((B, c), Open)) C
136 | -- => , (\c -> ((B, c), Open)) R
137 | -- => ]
138 | --
139 | -- => [ ((T, L), Open)
140 | -- => , ((T, C), Open)
141 | -- => , ((T, R), Open)
142 | -- => , ((M, L), Open)
143 | -- => , ((M, C), Open)
144 | -- => , ((M, R), Open)
145 | -- => , ((B, L), Open)
146 | -- => , ((B, C), Open)
147 | -- => , ((B, R), Open)
148 | -- => ]
149 | ```
150 |
151 | ### Monad and non-determinism
152 |
153 | The heart of the minimax algorithm is playing out a hypothetical future where
154 | each available move is made to see which one works out best. The `Monad`
155 | instance for `[]` is perfect for this problem when we think of lists as
156 | representing one non-deterministic value rather than a list of many
157 | deterministic ones.
158 |
159 | The list `[1, 2, 3]` represents a single number that is any one of `1`, `2`, or
160 | `3` at once. The type of this value is `[Int]`. The `Int` tells us the type of
161 | the value we're dealing with and the `[]` tells us that it's many values at
162 | once.
163 |
164 | Under this interpretation, `Functor`'s `fmap` represents *changing*
165 | probabilities: we have a number that can be any of `1`, `2`, or `3`. When we
166 | `fmap (+1)`, we get back a number that can be any of `2`, `3`, or `4`. We've
167 | changed the non-determinism without changing *how much* non-determinism there
168 | is. That fact, that `fmap` can't increase or decrease the non-determinism, is
169 | actually guaranteed through the Functor laws.
170 |
171 | ```haskell
172 | fmap (+1) [1, 2, 3]
173 | -- => [2, 3, 4]
174 | ```
175 |
176 | `Applicative`'s `(<*>)` can be thought of as *combining* probabilities. Given a
177 | function that can be any of `(+1)`, `(+2)`, or `(+3)` and a number that can be
178 | any of `1`, `2`, or `3`, `(<*>)` will give us a new number that can be any of
179 | the combined results of applying each possible function to each possible value.
180 |
181 | ```haskell
182 | [(+1), (+2), (+3)] <*> [1, 2, 3]
183 | -- => [2,3,4,3,4,5,4,5,6]
184 | ```
185 |
186 | Finally, `Monad`'s `(>>=)` is used to *expand* probabilities. Looking at its
187 | type again:
188 |
189 | ```haskell
190 | (>>=) :: m a -> (a -> m b) -> m b
191 | ```
192 |
193 | And specializing this to lists:
194 |
195 | ```haskell
196 | -- m a -> (a -> m b) -> m b
197 | (>>=) :: [] a -> (a -> [] b) -> [] b
198 | ```
199 |
200 | We can see that it takes an `a` that can be one of many values, and a function
201 | from `a` to `[b]`, i.e. a `b` that can be one of many values. `(>>=)` applies
202 | the function `(a -> [b])` to every `a` in the input list. The result must be
203 | `[[b]]`. To return the required type `[b]`, the list is then flattened. Because
204 | the types are so generic, this is the only implementation this function can
205 | have. If we rule out obvious mistakes like ignoring arguments and returning an
206 | empty list, reordering the list, or adding or dropping elements, the only way to
207 | define this function is to map, then flatten.
208 |
209 | ```haskell
210 | xs >>= f = concat (map f xs)
211 | ```
212 |
213 | Given our same number, one that can be any of `1`, `2`, or `3`, and a function
214 | that takes a (deterministic) number and produces a new set of possibilities,
215 | `(>>=)` will expand the probability space:
216 |
217 | ```haskell
218 | next :: Int -> [Int]
219 | next n = [n - 1, n, n + 1]
220 |
221 | [1, 2, 3] >>= next
222 | -- => concat (map next [1, 2, 3])
223 | -- => concat [[1 - 1, 1, 1 + 1], [2 - 1, 2, 2 + 1], [3 - 1, 3, 3 + 1]]
224 | -- => [0,1,2,1,2,3,2,3,4]
225 | ```
226 |
227 | We can continue expanding by repeatedly using `(>>=)`:
228 |
229 | ```haskell
230 | [1, 2, 3] >>= next >>= next
231 | -- => [-1,0,1,0,1,2,1,2,3,0,1,2,1,2,3,2,3,4,1,2,3,2,3,4,3,4,5]
232 | ```
233 |
234 | If we picture the `next` function as a step in time, going from some current
235 | state to multiple possible next states, we can think of `>>= next >>= next` as
236 | looking two steps into the future, exploring the possible states reachable from
237 | possible states.
238 |
239 | ### The Future
240 |
241 | If the theory above didn't make complete sense, that's OK. Let's get back to our
242 | Tic-Tac-Toe program and see how this works in the context of a real-word
243 | example.
244 |
245 | When it's our turn (us being the computer player), we want to play out the next
246 | turn for every move we have available. For each of those next turns, we want to
247 | do the same thing again. We want to repeat this process until the game is over.
248 | At that point, we can see which choice led to the best result and use that one.
249 |
250 | One thing we'll need, and our first opportunity to use `Monad`, is to find all
251 | available moves for a given `Board`:
252 |
253 | ```haskell
254 | available :: Board -> [Position]
255 | available board = do
256 | (position, Open) <- board
257 |
258 | return position
259 | ```
260 |
261 | In this expression, we're treating a `Board` as a list of `Space`s. In other
262 | words, it's one `Space` that is all of the spaces on the board at once. We're
263 | using `(>>=)`, through *do-notation*, to map, then flatten, each `Space` to its
264 | `Position`. We're using *do-notation* to take advantage of the fact that if we
265 | use a pattern in the left-hand side of `(<-)`, but the value doesn't match the
266 | pattern, it's discarded. This expression is a concise map-filter that relies on
267 | `(>>=)` to do the mapping and pattern matching to do the filtering.
268 |
269 | ### Return
270 |
271 | The `return` function, seen at the end of `available`, is not like `return`
272 | statements you'll find in other languages. Specifically, it does not abort the
273 | computation, presenting its argument as the return value for the function call.
274 | Nor is it always required at the end of a monadic expression. `return` is
275 | another function from the `Monad` type class. Its job is to take some value of
276 | type `a` and make it an `m a`. Conceptually, it should do this by putting the
277 | value in some default or minimal context. For `Maybe` this means applying
278 | `Just`. For `[]`, we put the value in a singleton list:
279 |
280 | ```haskell
281 | -- a -> m a
282 | return :: a -> [] a
283 | return x = [x]
284 | ```
285 |
286 | In our example, `position` is of type `Position` (i.e. `a`) and we need the
287 | expression to have type `[Position]` (i.e. `m a`), so `return position` does
288 | that.
289 |
290 | Another `Monad`-using function of the minimax algorithm is one that expands a
291 | given board into the end-states reached when each player plays all potential
292 | moves:
293 |
294 | ```haskell
295 | future :: Player -> Board -> [Board]
296 | future player board = do
297 | if over board
298 | then return board
299 | else do
300 | space <- available board
301 |
302 | future (opponent player) (play player space board)
303 | ```
304 |
305 | First we check if the `Board` is `over`. If that's the case, the future is a
306 | singleton list of only that `Board`--again, `return board` does that.
307 | Otherwise, we explore all available spaces. For each of them, we explore into
308 | the future again, this time for our opponent on a `Board` where we've played
309 | that space. This process repeats until someone wins or we fill the board in a
310 | draw. To fit this function into our Tic-Tac-Toe-playing program, we would score
311 | each path as we explore it and play the path with the best score.
312 |
313 | While a full program like this is very interesting, it quickly gets complicated
314 | with things not important to our discussion. To see a complete definition of a
315 | minimax-using Tic-Tac-Toe-playing program written in Ruby, check out Never Stop
316 | Building's [Understanding Minimax][minimax-post].
317 |
318 | [minimax-post]: http://neverstopbuilding.com/minimax
319 |
--------------------------------------------------------------------------------
/book/sample.md:
--------------------------------------------------------------------------------
1 | % Maybe Haskell
2 | % Pat Brisbin
3 |
4 | \clearpage
5 |
6 | # Introduction
7 |
8 | <<[introduction.md]
9 |
10 | \mainmatter
11 |
12 | # Haskell Basics
13 |
14 | <<[haskell-basics/functions.md]
15 |
16 | <<[haskell-basics/data-types.md]
17 |
18 | <<[haskell-basics/maybe.md]
19 |
20 | # Functor
21 |
22 | <<[functor/choices.md]
23 |
24 | <<[functor/functor.md]
25 |
26 | <<[functor/curried-form.md]
27 |
28 | # Applicative
29 |
30 | <<[applicative/follow-the-types.md]
31 |
32 | <<[applicative/apply.md]
33 |
34 | <<[applicative/chaining.md]
35 |
36 | # Other Types
37 |
38 | ## IO
39 |
40 | <<[other-types/io/other-instances.md]
41 |
--------------------------------------------------------------------------------
/book/whats-next.md:
--------------------------------------------------------------------------------
1 | At the start of this book, I said my intention was not to teach you Haskell.
2 | Instead, my goal was to give you a sense of writing realistic code that takes
3 | advantage of an uncommon feature found in the Haskell language. I wanted to
4 | strike a balance between short sound-bites without much depth and the large
5 | investment of time required to become proficient in the language.
6 |
7 | The central theme, the `Maybe` type, is an example of Haskell's principled
8 | stance resulting in tangible benefit for programmers. The frustration caused by
9 | Tony Hoare's self-proclaimed ["billion-dollar mistake"][mistake] is something
10 | I'll gladly live without. This same principled stance has lead to many similar
11 | outcomes in the Haskell language. From monadic I/O to advanced concurrency
12 | primitives, Haskell is full of constructs only made possible through slow and
13 | thoughtful language design. My hope is that by seeing--and really
14 | understanding--the relatively small example that is `Maybe`, you'll be motivated
15 | to explore the language further.
16 |
17 | [mistake]: http://en.wikipedia.org/wiki/Tony_Hoare#Apologies_and_retractions
18 |
19 | If you are so inclined, there are many resources online for getting up and
20 | running, what to read, etc. I mentioned Chris Allan's [learning
21 | path][learnhaskell] already. There's also [Haskell in 5 steps][steps]. I'm a
22 | huge fan of [Learn You a Haskell for Great Good!][lyah] and [Real World
23 | Haskell][rwh] if you're looking for books. If you prefer an exercise-based
24 | approach, we have a [Haskell Fundamentals][trail] trail on Upcase. Finally,
25 | don't be afraid to read academic papers. They are dense sources of very good
26 | information.
27 |
28 | [steps]: https://wiki.haskell.org/Haskell_in_5_steps
29 | [lyah]: http://learnyouahaskell.com/
30 | [rwh]: http://book.realworldhaskell.org/
31 | [trail]: https://upcase.com/haskell-fundamentals
32 |
--------------------------------------------------------------------------------
/release/images/cover.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtbot/maybe_haskell/af2130d3e040ba15281141360210c525f70fb0ca/release/images/cover.pdf
--------------------------------------------------------------------------------
/release/images/cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtbot/maybe_haskell/af2130d3e040ba15281141360210c525f70fb0ca/release/images/cover.png
--------------------------------------------------------------------------------
/release/images/fmap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtbot/maybe_haskell/af2130d3e040ba15281141360210c525f70fb0ca/release/images/fmap.png
--------------------------------------------------------------------------------
/release/maybe_haskell.epub:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtbot/maybe_haskell/af2130d3e040ba15281141360210c525f70fb0ca/release/maybe_haskell.epub
--------------------------------------------------------------------------------
/release/maybe_haskell.html.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtbot/maybe_haskell/af2130d3e040ba15281141360210c525f70fb0ca/release/maybe_haskell.html.zip
--------------------------------------------------------------------------------
/release/maybe_haskell.mobi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtbot/maybe_haskell/af2130d3e040ba15281141360210c525f70fb0ca/release/maybe_haskell.mobi
--------------------------------------------------------------------------------
/release/maybe_haskell.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thoughtbot/maybe_haskell/af2130d3e040ba15281141360210c525f70fb0ca/release/maybe_haskell.pdf
--------------------------------------------------------------------------------
/release/maybe_haskell.toc.html:
--------------------------------------------------------------------------------
1 |
2 | Table of Contents
3 |
4 | - Introduction
5 | - Haskell Basics
6 | - Functor
7 | - Applicative
8 | - Monad
9 | - Other Types
10 | - What's Next
11 |
12 |
13 |
--------------------------------------------------------------------------------