├── .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 | 12 |
13 | --------------------------------------------------------------------------------