lecture 15

This commit is contained in:
Joel Kaasinen
2021-05-27 10:32:40 +03:00
parent ad7b8edb45
commit 05cbb774f7
5 changed files with 1264 additions and 1 deletions
+109
View File
@@ -0,0 +1,109 @@
module Examples.Validation (Validation,invalid,check) where
import Control.Applicative
import Data.Char (isDigit)
data Validation a = Ok a | Errors [String]
deriving (Show,Eq)
instance Functor Validation where
fmap f (Ok x) = Ok (f x)
fmap _ (Errors e) = Errors e
instance Applicative Validation where
pure x = Ok x
liftA2 f (Ok x) (Ok y) = Ok (f x y)
liftA2 f (Errors e1) (Ok y) = Errors e1
liftA2 f (Ok x) (Errors e2) = Errors e2
liftA2 f (Errors e1) (Errors e2) = Errors (e1++e2)
invalid :: String -> Validation a
invalid err = Errors [err]
check :: Bool -> String -> a -> Validation a
check b err x
| b = pure x
| otherwise = invalid err
----
---- Example
----
birthday :: String -> Int -> Validation String
birthday name age = liftA2 congratulate checkedName checkedAge
where checkedName = check (length name < 10) "Name too long" name
checkedAge = check (age < 99) "Too old" age
congratulate n a = "Happy "++show a++"th birthday "++n++"!"
-- birthday "Guy" 31
-- ==> Ok "Happy 31th birthday Guy!"
-- birthday "Guybrush Threepwood" 31
-- ==> Errors ["Name too long"]
-- birthday "Yog-sothoth" 10000
-- ==> Errors ["Name too long","Too old"]
----
---- Example: validating lists
----
-- via recursion
allPositive :: [Int] -> Validation [Int]
allPositive [] = Ok []
allPositive (x:xs) = liftA2 (:) checkThis checkRest
where checkThis = check (x>=0) ("Not positive: "++show x) x
checkRest = allPositive xs
-- allPositive [1,2,3] ==> Ok [1,2,3]
-- allPositive [1,2,3,-4] ==> Errors ["Not positive: -4"]
-- allPositive [1,-2,3,-4] ==> Errors ["Not positive: -2","Not positive: -4"]
-- via traverse
allPositive' :: [Int] -> Validation [Int]
allPositive' xs = traverse checkNumber xs
where checkNumber x = check (x>=0) ("Not positive: "++show x) x
---
--- Alternative instance
---
instance Alternative Validation where
empty = Errors []
Ok x <|> _ = Ok x
Errors e1 <|> Ok y = Ok y
Errors e1 <|> Errors e2 = Errors (e1++e2)
----
---- Example: parsing contact information:
----
data ContactInfo = Email String | Phone String
deriving Show
validateEmail :: String -> Validation ContactInfo
validateEmail s = check (elem '@' s) "Not an email: should contain a @" (Email s)
checkLength :: String -> Validation ContactInfo
checkLength s = check (length s <= 10) "Not a phone number: should be at most 10 digits" (Phone s)
checkDigits :: String -> Validation ContactInfo
checkDigits s = check (all isDigit s) "Not a phone number: should be all numbers" (Phone s)
validatePhone :: String -> Validation ContactInfo
validatePhone s = checkDigits s *> checkLength s
validateContactInfo :: String -> Validation ContactInfo
validateContactInfo s = validateEmail s <|> validatePhone s
-- validateContactInfo "user@example.com"
-- ==> Ok (Email "user@example.com")
-- validateContactInfo "01234"
-- ==> Ok (Phone "01234")
-- validateContactInfo "01234567890"
-- ==> Errors ["Not an email: should contain a @","Not a phone number: should be at most 10 digits"]
-- validateContactInfo "01234567890x"
-- ==> Errors ["Not an email: should contain a @",
-- "Not a phone number: should be all numbers",
-- "Not a phone number: should be at most 10 digits"]
-- validateContactInfo "x"
-- ==> Errors ["Not an email: should contain a @",
-- "Not a phone number: should be all numbers"]
+6
View File
@@ -230,6 +230,11 @@ testing call = do
-- TH pprint prints all names as qualified, let's convert the names to unqualified locals
unqualifyName (Name n _) = Name n NameS
unqualifyType :: Type -> Type
unqualifyType (AppT f x) = AppT (unqualifyType f) (unqualifyType x)
unqualifyType (ConT n) = ConT (unqualifyName n)
unqualifyType x = error $ "Unsupported: " ++ show x
unqualify :: Exp -> Exp
unqualify (VarE n) = VarE (unqualifyName n)
unqualify (UnboundVarE n) = UnboundVarE (unqualifyName n)
@@ -241,6 +246,7 @@ unqualify (LitE l) = LitE l
unqualify (TupE exps) = TupE (map (fmap unqualify) exps)
unqualify (ListE exps) = ListE (map unqualify exps)
unqualify (ArithSeqE (FromR x)) = ArithSeqE (FromR (unqualify x))
unqualify (SigE e t) = SigE (unqualify e) (unqualifyType t)
unqualify x = error $ "Unsupported: " ++ show x
testing' :: Q Exp -> Q Exp
+371
View File
@@ -0,0 +1,371 @@
module Set15 where
import Mooc.Todo
import Examples.Validation
import Control.Applicative
import Data.Char
import Text.Read (readMaybe)
------------------------------------------------------------------------------
-- Ex 1: Sum two Maybe Int values using Applicative operations (i.e.
-- liftA2 and pure). Don't use pattern matching.
--
-- Examples:
-- sumTwoMaybes (Just 1) (Just 2) ==> Just 3
-- sumTwoMaybes (Just 1) Nothing ==> Nothing
-- sumTwoMaybes Nothing Nothing ==> Nothing
sumTwoMaybes :: Maybe Int -> Maybe Int -> Maybe Int
sumTwoMaybes = todo
------------------------------------------------------------------------------
-- Ex 2: Given two lists of words, xs and ys, generate all statements
-- of the form "x is [not] y". Use Applicative
-- operations like liftA2!
--
-- The order of the results doesn't matter.
--
-- Examples:
-- statements ["beauty"] ["suffering"]
-- ==> ["beauty is suffering","beauty is not suffering"]
-- statements ["beauty","code"] ["suffering","life"]
-- ==> ["beauty is suffering","beauty is life",
-- "beauty is not suffering","beauty is not life",
-- "code is suffering","code is life",
-- "code is not suffering","code is not life"]
statements :: [String] -> [String] -> [String]
statements = todo
------------------------------------------------------------------------------
-- Ex 3: A simple calculator with error handling. Given an operation
-- (negate or double) and a number, as strings, compute the result.
-- Return Nothing for an unknown operation or invalid number.
--
-- Use Applicative operations, don't use pattern matching.
--
-- Hint: remember the function readMaybe
--
-- Examples:
-- calculator "negate" "3" ==> Just (-3)
-- calculator "double" "7" ==> Just 14
-- calculator "doubl" "7" ==> Nothing
-- calculator "double" "7x" ==> Nothing
calculator :: String -> String -> Maybe Int
calculator = todo
------------------------------------------------------------------------------
-- Ex 4: Safe division. Implement the function validateDiv that
-- divides two integers, but returns an error ("Division by zero!") if
-- the divisor is zero.
--
-- NB! The constructors of Validation are not exported, so you can't
-- pattern match on Validation, you must use the Applicative methods
-- and the invalid and check functions.
--
-- Examples:
-- validateDiv 6 2 ==> Ok 3
-- validateDiv 6 0 ==> Errors ["Division by zero!"]
-- validateDiv 0 3 ==> Ok 0
validateDiv :: Int -> Int -> Validation Int
validateDiv = todo
------------------------------------------------------------------------------
-- Ex 5: Validating street addresses. A street address consists of a
-- street name, a street number, and a postcode.
--
-- Implement the functoin validateAddress which constructs an Address
-- value if the input is valid:
--
-- * Street length should be at most 20 characters
-- (if not, error "Invalid street name")
-- * Street number should only contain digits
-- (if not, error "Invalid street number")
-- * Postcode should be exactly five digits long
-- (if not, error "Invalid postcode")
--
-- Examples:
-- validateAddress "Haskell road" "35" "13337"
-- ==> Ok (Address "Haskell road" "35" "13337")
-- validateAddress "Haskell road" "35a" "13337"
-- ==> Errors ["Invalid street number"]
-- validateAddress "Haskell road" "35a" "1333"
-- ==> Errors ["Invalid street number","Invalid postcode"]
-- validateAddress "Haskeller's favourite road" "35a" "1333"
-- ==> Errors ["Invalid street name","Invalid street number","Invalid postcode"]
data Address = Address String String String
deriving (Show,Eq)
validateAddress :: String -> String -> String -> Validation Address
validateAddress streetName streetNumber postCode = todo
------------------------------------------------------------------------------
-- Ex 6: Given the names, ages and employment statuses of two
-- persons, wrapped in Applicatives, return a list of two Person
-- values, wrapped in an applicative.
--
-- Examples:
-- twoPersons (Just "Clarice") (Just 35) (Just True) (Just "Hannibal") (Just 50) (Just False)
-- ==> Just [Person "Clarice" 35 True,Person "Hannibal" 50 False]
-- twoPersons (Just "Clarice") (Just 35) (Just True) (Just "Hannibal") Nothing (Just False)
-- ==> Nothing
-- twoPersons ["Clarice"] [25,35] [True] ["Hannibal"] [50] [False]
-- ==> [[Person "Clarice" 25 True,Person "Hannibal" 50 False],
-- [Person "Clarice" 35 True,Person "Hannibal" 50 False]]
data Person = Person String Int Bool
deriving (Show, Eq)
twoPersons :: Applicative f =>
f String -> f Int -> f Bool -> f String -> f Int -> f Bool
-> f [Person]
twoPersons name1 age1 employed1 name2 age2 employed2 = todo
------------------------------------------------------------------------------
-- Ex 7: Validate a String that's either a Bool or an Int. The return
-- type of the function uses Either Bool Int to be able to represent
-- both cases. Use <|> to combine two validators and to produce two
-- errors if the value is not an Int or a Bool.
--
-- Hint: remember readMaybe
--
-- Examples:
-- boolOrInt "True" ==> Ok (Left True)
-- boolOrInt "13" ==> Ok (Right 13)
-- boolOrInt "13.2" ==> Errors ["Not a Bool","Not an Int"]
-- boolOrInt "Falseb" ==> Errors ["Not a Bool","Not an Int"]
boolOrInt :: String -> Validation (Either Bool Int)
boolOrInt = todo
------------------------------------------------------------------------------
-- Ex 8: Improved phone number validation. Implement the function
-- normalizePhone that, given a String:
--
-- * removes all spaces from the string
-- * checks that there are at most 10 remaining characters
-- * checks that all remaining characters are digits, and logs an
-- error for every nonvalid character
-- * returns the string, stripped of whitespace, if no errors
--
-- Examples:
-- normalizePhone "123 456 78" ==> Ok "12345678"
-- normalizePhone "123 4x6 78"
-- ==> Errors ["Invalid character: x"]
-- normalizePhone "123 4x6 7y"
-- ==> Errors ["Invalid character: x","Invalid character: y"]
-- normalizePhone "123 4x6 7y 999"
-- ==> Errors ["Too long","Invalid character: x","Invalid character: y"]
-- normalizePhone "123 456 78 999"
-- ==> Errors ["Too long"]
normalizePhone :: String -> Validation String
normalizePhone = todo
------------------------------------------------------------------------------
-- Ex 9: Parsing expressions. The Expression type describes an
-- arithmetic expression that has an operator (+ or -) and two
-- arguments that can be either numbers or single-letter variables.
-- The operator and the arguments are always separated by spaces. Here
-- are some examples of expressions like this: 1 + 2, y + 7, z - w
--
-- Implement the function parseExpression that uses the Validation
-- applicative to convert strings like "y + 7" to Expression values
-- like Plus (Variable 'y') (Number 7).
--
-- The parser should produce the following errors:
-- * For operators other than + or -: "Unknown operator: %"
-- * For variables that aren't single letters: "Invalid variable: xy"
-- * For arguments that aren't numbers: "Invalid number: 1x" --
-- * For expressions that don't consist of three words:
-- "Invalid expression: 1 + 2 +"
-- "Invalid expression: 1 -"
--
-- Hint: The functions `words` and `isAlpha`
--
-- Hint: If you have problems with the ordering of errors, remember
-- that Validation collects errors left-to-right!
--
-- Examples:
-- parseExpression "1 + 2" ==> Ok (Plus (Number 1) (Number 2))
-- parseExpression "z - A" ==> Ok (Minus (Variable 'z') (Variable 'A'))
-- parseExpression "1 * 2" ==> Errors ["Unknown operator: *"]
-- parseExpression "1 + 2x"
-- ==> Errors ["Invalid number: 2x","Invalid variable: 2x"]
-- parseExpression ". % 2x"
-- ==> Errors ["Unknown operator: %",
-- "Invalid number: .","Invalid variable: .",
-- "Invalid number: 2x","Invalid variable: 2x"]
data Arg = Number Int | Variable Char
deriving (Show, Eq)
data Expression = Plus Arg Arg | Minus Arg Arg
deriving (Show, Eq)
parseExpression :: String -> Validation Expression
parseExpression = todo
------------------------------------------------------------------------------
-- Ex 10: The Priced T type tracks a value of type T, and a price
-- (represented by an Int). Implement the Functor and Applicative
-- instances for Priced. They should work like this:
--
-- * Transforming a Priced value with fmap keeps the price the same
-- * pure should create a value with price 0
-- * liftA2 should sum the prices of the things to be combined
--
-- Examples:
-- fmap reverse (Priced 3 "abc")
-- ==> Priced 3 "cba"
-- liftA2 (*) (pure 2) (pure 3) :: Priced Int
-- ==> Priced 0 6
-- liftA2 (+) (Priced 1 3) (Priced 1 5)
-- ==> Priced 2 8
-- traverse (\x -> Priced (length x) x) ["abc","de","f"]
-- ==> Priced 6 ["abc","de","f"]
data Priced a = Priced Int a
deriving (Show, Eq)
instance Functor Priced where
fmap = todo
instance Applicative Priced where
pure = todo
liftA2 = todo
------------------------------------------------------------------------------
-- Ex 11: This and the next exercise will use a copy of the
-- Applicative type class called MyApplicative. MyApplicative lacks
-- the Functor requirement that Applicative has, and also the <*> type
-- class method. You'll get to implement them instead.
--
-- First you'll reimplement <*> using liftA2. In practical terms,
-- implement the operator <#> that works like <*>, using myPure and
-- myLiftA2.
--
-- As long as you get the types right, your implementation is pretty
-- much guaranteed to be correct.
--
-- Examples:
-- Just succ <#> Just 2 ==> Just 3
-- Nothing <#> Just 2 ==> Nothing
-- [(*2),(+1)] <#> [10,100] ==> [20,200,11,101]
class MyApplicative f where
myPure :: a -> f a
myLiftA2 :: (a -> b -> c) -> f a -> f b -> f c
-- Some instances for testing:
instance MyApplicative Maybe where
myPure = pure
myLiftA2 = liftA2
instance MyApplicative [] where
myPure = pure
myLiftA2 = liftA2
(<#>) :: MyApplicative f => f (a -> b) -> f a -> f b
f <#> x = todo
------------------------------------------------------------------------------
-- Ex 12: Reimplement fmap using liftA2 and pure. In practical terms,
-- implement the function myFmap below using the methods myPure and
-- myLiftA2 from the type class MyApplicative.
--
-- As long as you get the types right, your implementation is pretty
-- much guaranteed to be correct. However, this time there are a
-- couple of different possible implementations!
--
-- Examples:
-- myFmap negate (Just 1) ==> Just (-1)
-- myFmap negate Nothing ==> Nothing
-- myFmap negate [1,2,3] ==> [-1,-2,-3]
myFmap :: MyApplicative f => (a -> b) -> f a -> f b
myFmap = todo
------------------------------------------------------------------------------
-- Ex 13: Given a function that returns an Alternative value, and a
-- list, try the function on all the elements in the list and produce
-- any successes.
--
-- Hint: traverse won't help you since it succeeds only if all the
-- calls succeed. You need to use <|>.
--
-- Examples:
--
-- The Maybe Applicative returns the first success:
-- tryAll (\x -> if x>0 then pure x else empty) [0,3,2] :: Maybe Int
-- ==> Just 3
-- tryAll (\x -> if x>0 then pure x else empty) [0,-1,0] :: Maybe Int
-- ==> Nothing
-- The list Applicative returns all successes:
-- tryAll (\x -> if x>0 then pure x else empty) [0,3,2] :: [Int]
-- ==> [3,2]
-- The Validation Applicative returns the first success or all errors:
-- tryAll (\x -> if x>0 then pure x else invalid "zero") [0,3,2]
-- ==> Ok 3
-- tryAll (\x -> if x>0 then pure x else invalid "zero") [0,0,0]
-- ==> Errors ["zero","zero","zero"]
tryAll :: Alternative f => (a -> f b) -> [a] -> f b
tryAll = todo
------------------------------------------------------------------------------
-- Ex 14: Here's the type `Both` that expresses the composition of
-- functors. Here are some example values and types:
--
-- Both (Just [True]) :: Both Maybe [] Bool
-- Both [Just True, Nothing, Just False] :: Both [] Maybe Bool
-- Both [[True,False],[]] :: Both [] [] Bool
--
-- Both (Ok (Just "value")) :: Both Validation Maybe String
-- Both (Just (Errors ["wrong"])) :: Both Maybe Validation a
--
-- Implement a Functor instance for Both f g, given that f and g are
-- both Functors.
--
-- Examples:
-- fmap not (Both (Just [True])) ==> Both (Just [False])
-- fmap not (Both [Nothing]) ==> Both [Nothing]
-- fmap (+1) (Both [[1,2,3],[4,5]]) ==> Both [[2,3,4],[5,6]]
newtype Both f g a = Both (f (g a))
deriving Show
instance (Functor f, Functor g) => Functor (Both f g) where
fmap = todo
------------------------------------------------------------------------------
-- Ex 15: The composition of two Applicatives is also an Applicative!
-- Implement the instance Applicative (Both f g) (given that f and g
-- are already Applicatives).
--
-- Again, there's only one way to implement this that gets the types
-- right.
--
-- Examples:
-- pure 1 :: Both Maybe [] Int
-- ==> Both (Just [1])
-- liftA2 (+) (Both (Just [10,100])) (Both (Just [1,2]))
-- ==> Both (Just [11,12,101,102])
-- liftA2 (+) (Both (Just [10,100])) (Both Nothing)
-- ==> Both Nothing
-- liftA2 (&&) (Both (Just (invalid "err"))) (Both (Just (pure True)))
-- ==> Both (Just (Errors ["err"]))
-- liftA2 (&&) (Both (Just (invalid "err"))) (Both (Just (invalid "umm")))
-- ==> Both (Just (Errors ["err","umm"]))
-- liftA2 (+) (Both [pure 1, invalid "fail 1"])
-- (Both [pure 10, pure 100, invalid "fail 2"])
-- ==> Both [Ok 11,Ok 101,Errors ["fail 2"],
-- Errors ["fail 1"],Errors ["fail 1"],
-- Errors ["fail 1","fail 2"]]
instance (Applicative f, Applicative g) => Applicative (Both f g) where
pure = todo
liftA2 = todo
+260
View File
@@ -0,0 +1,260 @@
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables, StandaloneDeriving, FlexibleInstances #-}
module Set15Test where
import Mooc.Test
import Mooc.Th
import Examples.Validation
import Control.Applicative
import Test.QuickCheck hiding (Result,Fun,Failure)
import Set15
main = score tests
tests = [(1,"sumTwoMaybes",[ex1])
,(2,"statements",[ex2_1, ex2_2])
,(3,"calculator",[ex3_success, ex3_failure_1, ex3_failure_2])
,(4,"validateDiv",[ex4])
,(5,"validateAddress",[ex5_ok, ex5_fail])
,(6,"twoPersons",[ex6_maybe,ex6_list])
,(7,"boolOrInt",[ex7_ok, ex7_fail])
,(8,"normalizePhone",[ex8])
,(9,"parseExpression",[ex9_ok, ex9_fail])
,(10,"Priced",[ex10_fmap, ex10_liftA2])
,(11,"<*> via liftA2",[ex11])
,(12,"fmap via liftA2",[ex12])
,(14,"Functor Both",[ex14_ok, ex14_fail])
,(13,"tryAll",[ex13_maybe, ex13_list, ex13_validation])
,(15,"Applicative Both",[ex15_pure, ex15_liftA2, ex15_liftA2_2])
]
-- -- -- -- --
ex1 = forAll_ $ \i ->
forAll_ $ \j ->
conjoin [$(testing [|sumTwoMaybes (Just i) (Just j)|]) (?==Just (i+j))
,$(testing [|sumTwoMaybes (Just i) n|]) (?==Nothing)
,$(testing [|sumTwoMaybes n (Just j)|]) (?==Nothing)
,$(testing [|sumTwoMaybes n n|]) (?==Nothing)]
where n = Nothing :: Maybe Int
ex2_1 = conjoin
[$(testing [|statements ["x"] ["y"]|]) (hasElements ["x is y","x is not y"])
,$(testing [|statements ["x"] ["y","w"]|]) (hasElements ["x is y","x is w","x is not y","x is not w"])
,$(testing [|statements ["x","z"] ["y","w"]|]) (hasElements ["x is y","x is w","x is not y","x is not w"
,"z is y","z is w","z is not y","z is not w"])
,$(testing [|statements ([]::[String]) ["y","w"]|]) (?== [])]
word = listOf1 (choose ('a','z'))
ex2_2 = forAllBlind (resize 8 $ listOf1 word) $ \xs ->
forAllBlind (resize 8 $ listOf1 word) $ \ys ->
forAllBlind (elements xs) $ \x ->
forAllBlind (elements ys) $ \y ->
forAllBlind (elements [" is "," is not "]) $ \i ->
let exp = x ++ i ++ y
in $(testing [|statements xs ys|]) . was $ \out ->
counterexample (" Should contain "++show exp) $
elem exp out
ex3_success = forAllBlind (choose (-100,100)) $ \i ->
let s = show i
in conjoin [$(testing [|calculator "negate" s|]) (?==Just (negate i))
,$(testing [|calculator "double" s|]) (?==Just (2*i))]
ex3_failure_1 = forAllBlind word $ \w ->
forAllBlind (choose (-100,100::Int)) $ \i ->
not (elem w ["negate","double"]) ==> $(testing [|calculator w (show i)|]) (?==Nothing)
ex3_failure_2 = forAll (elements ["negate","double","xyzzy"]) $ \w ->
forAllBlind (choose (-100,100::Int)) $ \i ->
let s = show i
in conjoin [$(testing [|calculator w ""|]) (?==Nothing)
,$(testing [|calculator w (s++".3")|]) (?==Nothing)
,forAllBlind (shuffle (s++"z")) $ \s' -> $(testing [|calculator w s'|]) (?==Nothing)]
ok :: a -> Validation a
ok = pure
invalids :: [String] -> Validation a
invalids = foldr1 (<|>) . map invalid
ex4 = forAllBlind (choose (0,100)) $ \i ->
forAllBlind (choose (1,10)) $ \j ->
conjoin [$(testing [|validateDiv i j|]) (?==ok (div i j))
,$(testing [|validateDiv i 0|]) (?==invalid "Division by zero!")]
postCode = vectorOf 5 (choose ('0','9'))
street = listOf1 (elements (' ':['a'..'z'])) `suchThat` ((<=20).length)
ex5_ok = forAllBlind postCode $ \p ->
forAllBlind street $ \s ->
forAllBlind (fmap show (choose (1,1000::Int))) $ \n ->
$(testing [|validateAddress s n p|]) (?==ok (Address s n p))
ex5_fail = forAllBlind postCode $ \p ->
forAllBlind street $ \s ->
forAllBlind (fmap show (choose (1,1000::Int))) $ \n ->
forAllBlind (choose ('a','z')) $ \chaff ->
forAllBlind (vectorOf 20 (choose ('a','z'))) $ \pad ->
forAllBlind (shuffle (chaff:take 4 p)) $ \p' ->
forAllBlind (shuffle (chaff:n)) $ \n' ->
conjoin [$(testing [|validateAddress (s++pad) n p|]) (?==invalid "Invalid street name")
,$(testing [|validateAddress s n (take 4 p)|]) (?==invalid "Invalid postcode")
,$(testing [|validateAddress s n p'|]) (?==invalid "Invalid postcode")
,$(testing [|validateAddress s n' p|]) (?==invalid "Invalid street number")
,$(testing [|validateAddress (s++pad) n p'|]) (?==invalids ["Invalid street name", "Invalid postcode"])
,$(testing [|validateAddress (s++pad) n' (take 4 p)|]) (?==invalids ["Invalid street name", "Invalid street number","Invalid postcode"])]
ex6_maybe = forAllBlind word $ \name1 ->
forAllBlind word $ \name2 ->
forAllBlind (choose (10,100)) $ \age1 ->
forAllBlind (choose (10,100)) $ \age2 ->
forAll_ $ \(emp1,emp2) ->
conjoin [$(testing [|twoPersons (Just name1) (Just age1) (Just emp1) (Just name2) (Just age2) (Just emp2)|])
(?==Just [Person name1 age1 emp1, Person name2 age2 emp2])
,$(testing [|twoPersons (Just name1) (Nothing::Maybe Int) (Just emp1) (Just name2) (Just age2) (Just emp2)|])
(?==Nothing)
,$(testing [|twoPersons (Just name1) (Just age1) (Just emp1) (Just name2) (Just age2) (Nothing::Maybe Bool)|])
(?==Nothing)]
ex6_list = forAllBlind word $ \name1 ->
forAllBlind word $ \name2 ->
forAllBlind word $ \name3 ->
forAllBlind (choose (10,100)) $ \age1 ->
forAllBlind (choose (10,100)) $ \age2 ->
forAllBlind (choose (10,100)) $ \age3 ->
forAll_ $ \(emp1,emp2) ->
conjoin [$(testing [|twoPersons [name1] [age1] [emp1] [name2] [age2] [emp2]|])
(?==[[Person name1 age1 emp1, Person name2 age2 emp2]])
,$(testing [|twoPersons [name1,name3] [age1] [emp1] [name2] [age2] [emp2]|])
(?==[[Person name1 age1 emp1, Person name2 age2 emp2]
,[Person name3 age1 emp1, Person name2 age2 emp2]])
,$(testing [|twoPersons [name1] [age1] [emp1] [name2] [age2,age3] [emp2]|])
(?==[[Person name1 age1 emp1, Person name2 age2 emp2]
,[Person name1 age1 emp1, Person name2 age3 emp2]])]
ex7_ok = forAll_ $ \(i::Int) ->
forAll_ $ \(b::Bool) ->
conjoin [$(testing [|boolOrInt (show i)|]) (?==ok (Right i))
,$(testing [|boolOrInt (show b)|]) (?==ok (Left b))]
sow :: [a] -> [a] -> Gen [a]
sow xs [] = return xs
sow [] ys = return ys
sow (x:xs) (y:ys) = oneof [fmap (x:) $ sow xs (y:ys)
,fmap (y:) $ sow (x:xs) ys]
ex7_fail = forAll_ $ \(i::Int) ->
forAllBlind (choose ('a','z')) $ \c ->
forAllBlind (shuffle (c:show i)) $ \ni ->
forAll_ $ \(b::Bool) ->
forAllBlind (sow [c] (show b)) $ \nb ->
conjoin [$(testing [|boolOrInt ni|]) (?==invalids ["Not a Bool","Not an Int"])
,$(testing [|boolOrInt nb|]) (?==invalids ["Not a Bool","Not an Int"])]
digit = choose ('0','9')
ex8 = forAllBlind (take 10 <$> listOf1 digit) $ \out ->
forAllBlind (listOf1 (return ' ')) $ \spaces ->
forAllBlind word $ \chaff ->
forAllBlind (sow out spaces) $ \inp ->
forAllBlind (sow inp chaff) $ \wrong ->
conjoin [$(testing [|normalizePhone inp|]) (?==ok out)
,$(testing [|normalizePhone (inp++"9999999999")|]) (?==invalid "Too long")
,$(testing [|normalizePhone wrong|])
(?==invalids ((if length out + length chaff > 10 then ["Too long"] else [])++["Invalid character: "++[d] | d <- chaff]))]
showE (Plus x y) = showA x ++ " + " ++showA y
showE (Minus x y) = showA x ++ " - " ++showA y
showA (Number i) = show i
showA (Variable v) = [v]
genA = oneof [Number <$> choose (0,10)
,Variable <$> choose ('a','z')]
genE = elements [Plus,Minus] <*> genA <*> genA
ex9_ok = forAllBlind genE $ \exp ->
let s = showE exp
in $(testing [|parseExpression s|]) (?==ok exp)
ex9_fail = forAllBlind (showA<$>genA) $ \goodArg ->
forAllBlind (elements ["1z","1.0","xy","."]) $ \badArg ->
forAllBlind (elements ["+","-"]) $ \goodOp ->
forAllBlind (elements ["*","%","x","3"]) $ \badOp ->
let b x op y = x ++ " " ++ op ++ " " ++ y
badExp1 = (goodArg ++ " " ++ goodOp)
badExp2 = b goodArg goodOp goodArg ++ " " ++ goodOp
in conjoin [$(testing [|parseExpression (b goodArg goodOp badArg)|])
(?==invalids ["Invalid number: "++badArg, "Invalid variable: "++badArg])
,$(testing [|parseExpression (b badArg goodOp goodArg)|])
(?==invalids ["Invalid number: "++badArg, "Invalid variable: "++badArg])
,$(testing [|parseExpression (b goodArg badOp goodArg)|])
(?==invalid ("Unknown operator: "++badOp))
,$(testing [|parseExpression badExp1|])
(?==invalid ("Invalid expression: "++badExp1))
,$(testing [|parseExpression badExp2|])
(?==invalid ("Invalid expression: "++badExp2))
,$(testing [|parseExpression (b goodArg badOp badArg)|])
(?==invalids ["Unknown operator: "++badOp,"Invalid number: "++badArg, "Invalid variable: "++badArg])
,$(testing [|parseExpression (b goodArg badOp badArg)|])
(?==invalids ["Unknown operator: "++badOp,"Invalid number: "++badArg, "Invalid variable: "++badArg])]
ex10_fmap = conjoin [$(testing' [|fmap reverse (Priced 3 "abc")|]) (?==Priced 3 "cba")
,$(testing' [|fmap negate (Priced 1 7)|]) (?==Priced 1 (-7))]
ex10_liftA2 = conjoin [$(testing' [|liftA2 (++) (Priced 3 "abc") (Priced 5 "de")|]) (?==Priced 8 "abcde")
,$(testing' [|liftA2 (+) (pure 4) (Priced 3 6)|]) (?==Priced 3 10)]
deriving instance (Eq (f (g a))) => Eq (Both f g a)
ex11 = conjoin [$(testing' [|Just succ <#> Just 2|]) (?==Just 3)
,$(testing' [|Nothing <#> Just 2|]) (?==(Nothing :: Maybe Int))
,$(testing' [|Just reverse <#> Nothing|]) (?==(Nothing :: Maybe [Bool]))
,$(testing' [|[reverse,drop 1] <#> ["foo","bar"]|]) (?==["oof","rab","oo","ar"])]
ex12 = conjoin [$(testing' [|myFmap negate (Just 1)|]) (?==Just (-1))
,$(testing' [|myFmap negate Nothing|]) (?==Nothing)
,$(testing' [|myFmap negate [1,2]|]) (?==[-1,-2])
,$(testing' [|myFmap not [True,True,False]|]) (?==[False,False,True])
,$(testing' [|myFmap not Nothing|]) (?==Nothing)]
ex13_maybe = conjoin [$(testing' [|tryAll id [Nothing, Just 1, Just 2]|]) (?==Just 1)
,$(testing' [|tryAll id [Nothing, Nothing]|]) (?==(Nothing::Maybe Int))
,$(testing' [|tryAll id [] :: Maybe Int|]) (?==Nothing)]
ex13_list = conjoin [$(testing' [|tryAll tail ["abc", "d", "ef"]|]) (?=="bcf")
,$(testing' [|tryAll tail []|]) (?==([]::String))]
tA l xs k = counterexample' ("tryAll (\\x -> if x>" ++ show l ++ " then pure x else invalid \"zero\") "++show xs) $
k $ tryAll (\x -> if x>l then pure x else invalid "zero") xs
ex13_validation = forAllBlind (choose (0::Int,10)) $ \l ->
forAllBlind (listOf1 (choose (0::Int,10))) $ \xs ->
tA l xs (?==case filter (>l) xs of [] -> invalids (map (const "zero") xs)
(x:_) -> ok x)
ex14_ok = conjoin [$(testing' [|fmap not (Both (Just [True]))|]) (?== Both (Just [False]))
,$(testing' [|fmap negate (Both [Just 3, Just 4])|]) (?== Both [Just (-3), Just (-4)])
,$(testing' [|fmap negate (Both [[1,2,3],[4,5]])|]) (?== Both [[-1,-2,-3],[-4,-5]])]
ex14_fail = conjoin [$(testing' [|fmap not (Both [Nothing])|]) (?== Both [Nothing])
,$(testing' [|fmap not (Both []) :: Both [] Maybe Bool|]) (?== Both [])]
ex15_pure = conjoin [$(testing' [|pure 1 :: Both [] Maybe Int|]) (?== Both [Just 1])
,$(testing' [|pure "a" :: Both Maybe Validation String|]) (?==Both (Just (ok "a")))]
ex15_liftA2 = conjoin [$(testing' [|liftA2 (+) (Both (Just [10,100])) (Both (Just [1,2]))|]) (?==Both (Just [11,12,101,102]))
,$(testing' [|liftA2 (+) (Both (Just [10,100])) (Both Nothing)|]) (?==Both Nothing)]
ex15_liftA2_2 = conjoin [$(testing' [|liftA2 (&&) (Both (Just (invalid "err"))) (Both (Just (pure True)))|]) (?==Both (Just (invalid "err")))
,$(testing' [|liftA2 (&&) (Both (Just (invalid "err"))) (Both (Just (invalid "umm")))|]) (?==Both (Just (invalids ["err","umm"])))
,$(testing' [|liftA2 (+) (Both [pure 1, invalid "fail 1"]) (Both [pure 10, pure 100, invalid "fail 2"])|])
(?== Both [ok 11,ok 101,invalid "fail 2",
invalid "fail 1",invalid "fail 1",
invalids ["fail 1","fail 2"]])]
+518 -1
View File
@@ -158,6 +158,18 @@ code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warni
<li><a href="#working-with-a-database-sqlite-simple"><span class="toc-section-number">14.4</span> Working With a Database: sqlite-simple</a></li>
<li><a href="#exercises-5"><span class="toc-section-number">14.5</span> Exercises</a></li>
</ul></li>
<li><a href="#lecture-15-youre-valid-even-without-monads"><span class="toc-section-number">15</span> Lecture 15: You’re Valid Even Without Monads</a><ul>
<li><a href="#introduction-to-applicatives"><span class="toc-section-number">15.1</span> Introduction to Applicatives</a></li>
<li><a href="#the-list-applicative"><span class="toc-section-number">15.2</span> The List Applicative</a></li>
<li><a href="#new-operators"><span class="toc-section-number">15.3</span> New Operators</a></li>
<li><a href="#the-validation-applicative"><span class="toc-section-number">15.4</span> The Validation Applicative</a></li>
<li><a href="#validating-lists-traverse"><span class="toc-section-number">15.5</span> Validating Lists: <code>traverse</code></a></li>
<li><a href="#sidenote-traversable"><span class="toc-section-number">15.6</span> Sidenote: <code>Traversable</code></a></li>
<li><a href="#dealing-with-failure-alternative"><span class="toc-section-number">15.7</span> Dealing with Failure: <code>Alternative</code></a></li>
<li><a href="#sidenote-monads-and-applicatives"><span class="toc-section-number">15.8</span> Sidenote: Monads and Applicatives</a></li>
<li><a href="#quiz-5"><span class="toc-section-number">15.9</span> Quiz</a></li>
<li><a href="#exercises-6"><span class="toc-section-number">15.10</span> Exercises</a></li>
</ul></li>
</ul>
</nav>
<div id="text-container">
@@ -1922,7 +1934,7 @@ Prelude&gt; final
<a class="sourceLine" id="cb162-12" data-line-number="12">System.Directory.listDirectory<span class="ot"> ::</span> FilePath <span class="ot">-&gt;</span> <span class="dt">IO</span> [FilePath]</a>
<a class="sourceLine" id="cb162-13" data-line-number="13"><span class="co">-- is the given file a directory?</span></a>
<a class="sourceLine" id="cb162-14" data-line-number="14">System.Directory.doesDirectoryExist<span class="ot"> ::</span> FilePath <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">Bool</span></a></code></pre></div>
<p>And here’s the program itself. You can also find it in the course repository as <a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Example/ReadTypes.hs"><code>exercises/Examples/ReadTypes.hs</code></a>.</p>
<p>And here’s the program itself. You can also find it in the course repository as <a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Examples/ReadTypes.hs"><code>exercises/Examples/ReadTypes.hs</code></a>.</p>
<div class="sourceCode" id="cb163"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb163-1" data-line-number="1"><span class="kw">module</span> <span class="dt">Examples.ReadTypes</span> <span class="kw">where</span></a>
<a class="sourceLine" id="cb163-2" data-line-number="2"></a>
<a class="sourceLine" id="cb163-3" data-line-number="3"><span class="kw">import</span> <span class="dt">Control.Monad</span> (forM)</a>
@@ -3654,6 +3666,511 @@ bob
<li><a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set14b.hs">Set14b</a>: HTTP &amp; SQLite</li>
<li><a href="https://forms.gle/soVtMeGBxSo6u5zp6">Remember to give feedback!</a></li>
</ul>
<h1 id="lecture-15-youre-valid-even-without-monads"><span class="header-section-number">15</span> Lecture 15: You’re Valid Even Without Monads</h1>
<h2 id="introduction-to-applicatives"><span class="header-section-number">15.1</span> Introduction to Applicatives</h2>
<p>The <code>Applicative</code> type class is a middle ground between <code>Functor</code> (which you can’t do that much with) and <code>Monad</code> (which pretty much allows you to write arbitrary programs). Reasons to use <code>Applicative</code> instead of <code>Monad</code> include:</p>
<ul>
<li>Performance: since <code>Applicative</code> allows less operations, it can be optimized better than <code>Monad</code>.</li>
<li>Simplicity: an <code>Applicative</code> interface is easier to reason about.</li>
<li>Necessity: there just is no way to define a <code>Monad</code> instance for your type, but there is an <code>Applicative</code> instance. This is rare.</li>
</ul>
<p>So what is an <code>Applicative</code>? Let’s look at a definition.</p>
<div class="sourceCode" id="cb337"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb337-1" data-line-number="1"><span class="kw">class</span> <span class="dt">Functor</span> f <span class="ot">=&gt;</span> <span class="dt">Applicative</span> f <span class="kw">where</span></a>
<a class="sourceLine" id="cb337-2" data-line-number="2"><span class="ot"> pure ::</span> a <span class="ot">-&gt;</span> f a</a>
<a class="sourceLine" id="cb337-3" data-line-number="3"><span class="ot"> liftA2 ::</span> (a <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> c) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> f b <span class="ot">-&gt;</span> f c</a>
<a class="sourceLine" id="cb337-4" data-line-number="4"> <span class="co">-- other operations omitted for now</span></a></code></pre></div>
<p>So an <code>Applicative</code> is a <code>Functor</code> that allows us to build singleton values via <code>pure</code>, and combine two values into one using <code>liftA2</code>. This adds a lot of power compared to a bare functor. Computations using functors are necessarily linear: <code>fmap :: (a -&gt; b) -&gt; f a -&gt; f b</code> takes in one functorial value, and outputs another. By contrast, <code>pure</code> takes in no functorial value and outputs one, and <code>liftA2</code> takes in two and returns one.</p>
<p>Sidenote: the term Applicative comes from the term <a href="https://en.wikipedia.org/wiki/Applicative_functor">Applicative Functor</a>, which sounds like it comes from Category Theory, but was actually introduced in a programming paper.</p>
<p>That’s enough abstract mumbo jumbo for now. Let’s look at what sort of computations we can express using Applicative operations (and <code>fmap</code>). We’ll start with the <code>Maybe</code> applicative. Here’s a streamlined definition:</p>
<div class="sourceCode" id="cb338"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb338-1" data-line-number="1"><span class="kw">instance</span> <span class="dt">Applicative</span> <span class="dt">Maybe</span> <span class="kw">where</span></a>
<a class="sourceLine" id="cb338-2" data-line-number="2"> pure x <span class="fu">=</span> <span class="dt">Just</span> x</a>
<a class="sourceLine" id="cb338-3" data-line-number="3"> liftA2 f (<span class="dt">Just</span> x) (<span class="dt">Just</span> y) <span class="fu">=</span> <span class="dt">Just</span> (f x y)</a>
<a class="sourceLine" id="cb338-4" data-line-number="4"> liftA2 f <span class="dt">Nothing</span> (<span class="dt">Just</span> _) <span class="fu">=</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb338-5" data-line-number="5"> liftA2 f (<span class="dt">Just</span> _) <span class="dt">Nothing</span> <span class="fu">=</span> <span class="dt">Nothing</span></a></code></pre></div>
<!-- TODO some GHCi examples? -->
<p>You’ll see the definition uses the same type of failure propagation as the <code>Monad Maybe</code> instance. Let’s use this when parsing monetary values:</p>
<div class="sourceCode" id="cb339"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb339-1" data-line-number="1"><span class="kw">data</span> <span class="dt">Currency</span> <span class="fu">=</span> <span class="dt">EUR</span> <span class="fu">|</span> <span class="dt">USD</span></a>
<a class="sourceLine" id="cb339-2" data-line-number="2"> <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</a>
<a class="sourceLine" id="cb339-3" data-line-number="3"><span class="kw">data</span> <span class="dt">Money</span> <span class="fu">=</span> <span class="dt">Money</span> <span class="dt">Int</span> <span class="dt">Currency</span></a>
<a class="sourceLine" id="cb339-4" data-line-number="4"> <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</a>
<a class="sourceLine" id="cb339-5" data-line-number="5"></a>
<a class="sourceLine" id="cb339-6" data-line-number="6"><span class="ot">parseCurrency ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> <span class="dt">Currency</span></a>
<a class="sourceLine" id="cb339-7" data-line-number="7">parseCurrency <span class="st">&quot;e&quot;</span> <span class="fu">=</span> pure <span class="dt">EUR</span></a>
<a class="sourceLine" id="cb339-8" data-line-number="8">parseCurrency <span class="st">&quot;€&quot;</span> <span class="fu">=</span> pure <span class="dt">EUR</span></a>
<a class="sourceLine" id="cb339-9" data-line-number="9">parseCurrency <span class="st">&quot;$&quot;</span> <span class="fu">=</span> pure <span class="dt">USD</span></a>
<a class="sourceLine" id="cb339-10" data-line-number="10">parseCurrency _ <span class="fu">=</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb339-11" data-line-number="11"></a>
<a class="sourceLine" id="cb339-12" data-line-number="12"><span class="ot">parseAmount ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> <span class="dt">Int</span></a>
<a class="sourceLine" id="cb339-13" data-line-number="13">parseAmount <span class="fu">=</span> readMaybe</a>
<a class="sourceLine" id="cb339-14" data-line-number="14"></a>
<a class="sourceLine" id="cb339-15" data-line-number="15"><span class="ot">parseMoney ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> <span class="dt">Money</span></a>
<a class="sourceLine" id="cb339-16" data-line-number="16">parseMoney amountString currencyString <span class="fu">=</span></a>
<a class="sourceLine" id="cb339-17" data-line-number="17"> liftA2 <span class="dt">Money</span> (parseAmount amountString) (parseCurrency currencyString)</a></code></pre></div>
<div class="sourceCode" id="cb340"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb340-1" data-line-number="1">parseMoney <span class="st">&quot;123&quot;</span> <span class="st">&quot;€&quot;</span> <span class="fu">==&gt;</span> <span class="dt">Just</span> (<span class="dt">Money</span> <span class="dv">123</span> <span class="dt">EUR</span>)</a>
<a class="sourceLine" id="cb340-2" data-line-number="2">parseMoney <span class="st">&quot;45&quot;</span> <span class="st">&quot;$&quot;</span> <span class="fu">==&gt;</span> <span class="dt">Just</span> (<span class="dt">Money</span> <span class="dv">45</span> <span class="dt">USD</span>)</a>
<a class="sourceLine" id="cb340-3" data-line-number="3">parseMoney <span class="st">&quot;4x&quot;</span> <span class="st">&quot;€&quot;</span> <span class="fu">==&gt;</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb340-4" data-line-number="4">parseMoney <span class="st">&quot;45&quot;</span> <span class="st">&quot;£&quot;</span> <span class="fu">==&gt;</span> <span class="dt">Nothing</span></a></code></pre></div>
<p>That worked out nicely. However, if we try to expand on this we soon run into the limits of <code>Applicative</code>. For example, consider this <code>sumMoney</code> function that sums <code>Money</code> values but fails if they are not in the same currency:</p>
<div class="sourceCode" id="cb341"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb341-1" data-line-number="1"><span class="ot">sumMoney ::</span> <span class="dt">Money</span> <span class="ot">-&gt;</span> <span class="dt">Money</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> <span class="dt">Money</span></a>
<a class="sourceLine" id="cb341-2" data-line-number="2">sumMoney (<span class="dt">Money</span> a c) (<span class="dt">Money</span> b c&#39;)</a>
<a class="sourceLine" id="cb341-3" data-line-number="3"> <span class="fu">|</span> c <span class="fu">==</span> c&#39; <span class="fu">=</span> <span class="dt">Just</span> (<span class="dt">Money</span> (a<span class="fu">+</span>b) c)</a>
<a class="sourceLine" id="cb341-4" data-line-number="4"> <span class="fu">|</span> otherwise <span class="fu">=</span> <span class="dt">Nothing</span></a></code></pre></div>
<p>We can’t apply it to two <code>Maybe Money</code> values using <code>Applicative</code> operations. We need the <code>Maybe</code> monad for that:</p>
<div class="sourceCode" id="cb342"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb342-1" data-line-number="1"><span class="ot">example ::</span> <span class="dt">Maybe</span> <span class="dt">Money</span></a>
<a class="sourceLine" id="cb342-2" data-line-number="2">example <span class="fu">=</span> <span class="kw">do</span> x <span class="ot">&lt;-</span> parseMoney <span class="st">&quot;123&quot;</span> <span class="st">&quot;€&quot;</span></a>
<a class="sourceLine" id="cb342-3" data-line-number="3"> y <span class="ot">&lt;-</span> parseMoney <span class="st">&quot;45&quot;</span> <span class="st">&quot;$&quot;</span></a>
<a class="sourceLine" id="cb342-4" data-line-number="4"> sumMoney x y</a></code></pre></div>
<p>If we try to use <code>liftA2</code>, we’re stuck with a <code>Maybe (Maybe Money)</code> type. In addition, we can now get two different types of failures: <code>Nothing</code> and <code>Just Nothing</code>, depending on what level the error happens on. This would be a clear case for switching to a <code>Monad</code> instance.</p>
<pre><code>liftA2 sumMoney (parseMoney &quot;123&quot; &quot;e&quot;) (parseMoney &quot;45&quot; &quot;€&quot;)
==&gt; Just (Just (Money 168 EUR))
liftA2 sumMoney (parseMoney &quot;123&quot; &quot;e&quot;) (parseMoney &quot;45&quot; &quot;$&quot;)
==&gt; Just Nothing
liftA2 sumMoney (parseMoney &quot;123&quot; &quot;e&quot;) (parseMoney &quot;xxx&quot; &quot;e&quot;)
==&gt; Nothing</code></pre>
<p>Sidenote: the name <code>liftA2</code> sounds a bit cumbersome, but it’s an analogy with the <code>liftM</code>, <code>liftM2</code> and so on functions for monads. Recall that <code>liftM</code> was just <code>fmap</code>, so perhaps <code>liftA2</code> should’ve been called <code>fmap2</code>.</p>
<h2 id="the-list-applicative"><span class="header-section-number">15.2</span> The List Applicative</h2>
<p>Let’s have a look at the applicative instances for another <code>Functor</code> we’ve seen. The <code>Applicative</code> instance for the list functor goes through all possible combinations of values (just like the list monad). Here’s the instance:</p>
<div class="sourceCode" id="cb344"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb344-1" data-line-number="1"><span class="kw">instance</span> <span class="dt">Applicative</span> [] <span class="kw">where</span></a>
<a class="sourceLine" id="cb344-2" data-line-number="2"> pure x <span class="fu">=</span> [x]</a>
<a class="sourceLine" id="cb344-3" data-line-number="3"> liftA2 f xs ys <span class="fu">=</span> [f x y <span class="fu">|</span> x <span class="ot">&lt;-</span> xs, y <span class="ot">&lt;-</span> ys]</a></code></pre></div>
<p>And here’s an example: generating some phrases.</p>
<div class="sourceCode" id="cb345"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb345-1" data-line-number="1"><span class="ot">things ::</span> [<span class="dt">String</span>]</a>
<a class="sourceLine" id="cb345-2" data-line-number="2">things <span class="fu">=</span> [<span class="st">&quot;tangerine&quot;</span>,<span class="st">&quot;bandit&quot;</span>,<span class="st">&quot;diamond&quot;</span>]</a>
<a class="sourceLine" id="cb345-3" data-line-number="3"></a>
<a class="sourceLine" id="cb345-4" data-line-number="4"><span class="ot">fruits ::</span> [<span class="dt">String</span>]</a>
<a class="sourceLine" id="cb345-5" data-line-number="5">fruits <span class="fu">=</span> [<span class="st">&quot;apple&quot;</span>, <span class="st">&quot;tangerine&quot;</span>]</a>
<a class="sourceLine" id="cb345-6" data-line-number="6"></a>
<a class="sourceLine" id="cb345-7" data-line-number="7"><span class="ot">phrases ::</span> [<span class="dt">String</span>]</a>
<a class="sourceLine" id="cb345-8" data-line-number="8">phrases <span class="fu">=</span> liftA2 combine things fruits</a>
<a class="sourceLine" id="cb345-9" data-line-number="9"> <span class="kw">where</span> combine t f <span class="fu">=</span> <span class="st">&quot;a &quot;</span> <span class="fu">++</span> t <span class="fu">++</span> <span class="st">&quot; the size of a &quot;</span> <span class="fu">++</span> f</a>
<a class="sourceLine" id="cb345-10" data-line-number="10"></a>
<a class="sourceLine" id="cb345-11" data-line-number="11">bunches <span class="fu">=</span> liftA2 copy [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] fruits</a>
<a class="sourceLine" id="cb345-12" data-line-number="12"> <span class="kw">where</span> copy n f <span class="fu">=</span> unwords (replicate n f)</a></code></pre></div>
<div class="sourceCode" id="cb346"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb346-1" data-line-number="1">phrases <span class="fu">==&gt;</span> [<span class="st">&quot;a tangerine the size of a apple&quot;</span>,</a>
<a class="sourceLine" id="cb346-2" data-line-number="2"> <span class="st">&quot;a tangerine the size of a tangerine&quot;</span>,</a>
<a class="sourceLine" id="cb346-3" data-line-number="3"> <span class="st">&quot;a bandit the size of a apple&quot;</span>,</a>
<a class="sourceLine" id="cb346-4" data-line-number="4"> <span class="st">&quot;a bandit the size of a tangerine&quot;</span>,</a>
<a class="sourceLine" id="cb346-5" data-line-number="5"> <span class="st">&quot;a diamond the size of a apple&quot;</span>,</a>
<a class="sourceLine" id="cb346-6" data-line-number="6"> <span class="st">&quot;a diamond the size of a tangerine&quot;</span>]</a>
<a class="sourceLine" id="cb346-7" data-line-number="7"></a>
<a class="sourceLine" id="cb346-8" data-line-number="8">bunches <span class="fu">==&gt;</span> [<span class="st">&quot;apple&quot;</span>,<span class="st">&quot;tangerine&quot;</span>,</a>
<a class="sourceLine" id="cb346-9" data-line-number="9"> <span class="st">&quot;apple apple&quot;</span>,<span class="st">&quot;tangerine tangerine&quot;</span>,</a>
<a class="sourceLine" id="cb346-10" data-line-number="10"> <span class="st">&quot;apple apple apple&quot;</span>,<span class="st">&quot;tangerine tangerine tangerine&quot;</span>]</a></code></pre></div>
<!-- TODO more examples? -->
<h2 id="new-operators"><span class="header-section-number">15.3</span> New Operators</h2>
<p>There are a handful of operators for Applicatives that are quite handy. They are <code>&lt;$&gt;</code>, <code>&lt;*&gt;</code>, <code>&lt;*</code> and <code>*&gt;</code>.</p>
<p>Let’s start with <code>&lt;$&gt;</code>, which is just an infix version of <code>fmap</code>:</p>
<div class="sourceCode" id="cb347"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb347-1" data-line-number="1"><span class="ot">(&lt;$&gt;) ::</span> <span class="dt">Functor</span> f <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> f b</a>
<a class="sourceLine" id="cb347-2" data-line-number="2">f <span class="fu">&lt;$&gt;</span> x <span class="fu">=</span> fmap f x</a></code></pre></div>
<div class="sourceCode" id="cb348"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb348-1" data-line-number="1">not <span class="fu">&lt;$&gt;</span> <span class="dt">Just</span> <span class="dt">True</span> <span class="fu">==&gt;</span> <span class="dt">Just</span> <span class="dt">False</span></a>
<a class="sourceLine" id="cb348-2" data-line-number="2">not <span class="fu">&lt;$&gt;</span> <span class="dt">Nothing</span> <span class="fu">==&gt;</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb348-3" data-line-number="3">negate <span class="fu">&lt;$&gt;</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="fu">==&gt;</span> [<span class="fu">-</span><span class="dv">1</span>,<span class="fu">-</span><span class="dv">2</span>,<span class="fu">-</span><span class="dv">3</span>]</a></code></pre></div>
<p>That’s kinda nice on its own, but it really gets to shine when combined with this Applicative operator:</p>
<div class="sourceCode" id="cb349"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb349-1" data-line-number="1"><span class="ot">(&lt;*&gt;) ::</span> <span class="dt">Applicative</span> f <span class="ot">=&gt;</span> f (a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> f b</a></code></pre></div>
<p>The type tells you what <code>&lt;*&gt;</code> does: it’s function application <em>lifted</em> to an applicative. Here are some standalone examples:</p>
<div class="sourceCode" id="cb350"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb350-1" data-line-number="1"><span class="dt">Just</span> not <span class="fu">&lt;*&gt;</span> <span class="dt">Just</span> <span class="dt">True</span> <span class="fu">==&gt;</span> <span class="dt">Just</span> <span class="dt">False</span></a>
<a class="sourceLine" id="cb350-2" data-line-number="2"><span class="dt">Nothing</span> <span class="fu">&lt;*&gt;</span> <span class="dt">Just</span> <span class="dt">True</span> <span class="fu">==&gt;</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb350-3" data-line-number="3"><span class="dt">Just</span> not <span class="fu">&lt;*&gt;</span> <span class="dt">Nothing</span> <span class="fu">==&gt;</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb350-4" data-line-number="4">[(<span class="fu">+</span><span class="dv">1</span>),(<span class="fu">*</span><span class="dv">2</span>)] <span class="fu">&lt;*&gt;</span> [<span class="dv">10</span>,<span class="dv">100</span>] <span class="fu">==&gt;</span> [<span class="dv">11</span>,<span class="dv">101</span>,<span class="dv">20</span>,<span class="dv">200</span>]</a></code></pre></div>
<p>The real magic happens when we combine <code>&lt;$&gt;</code> and <code>&lt;*&gt;</code>: we can then lift functions of arbitrarily many argments to an Applicative!</p>
<div class="sourceCode" id="cb351"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb351-1" data-line-number="1"><span class="ot">say ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">String</span></a>
<a class="sourceLine" id="cb351-2" data-line-number="2">say x i y <span class="fu">=</span> x <span class="fu">++</span> <span class="st">&quot; has &quot;</span> <span class="fu">++</span> show i <span class="fu">++</span> <span class="st">&quot; &quot;</span> <span class="fu">++</span> y</a></code></pre></div>
<div class="sourceCode" id="cb352"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb352-1" data-line-number="1">say <span class="fu">&lt;$&gt;</span> <span class="dt">Just</span> <span class="st">&quot;haskell&quot;</span> <span class="fu">&lt;*&gt;</span> <span class="dt">Just</span> <span class="dv">99</span> <span class="fu">&lt;*&gt;</span> <span class="dt">Just</span> <span class="st">&quot;operators&quot;</span></a>
<a class="sourceLine" id="cb352-2" data-line-number="2"> <span class="fu">==&gt;</span> <span class="dt">Just</span> <span class="st">&quot;haskell has 99 operators&quot;</span></a>
<a class="sourceLine" id="cb352-3" data-line-number="3">say <span class="fu">&lt;$&gt;</span> <span class="dt">Nothing</span> <span class="fu">&lt;*&gt;</span> <span class="dt">Just</span> <span class="dv">99</span> <span class="fu">&lt;*&gt;</span> <span class="dt">Just</span> <span class="st">&quot;operators&quot;</span></a>
<a class="sourceLine" id="cb352-4" data-line-number="4"> <span class="fu">==&gt;</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb352-5" data-line-number="5">say <span class="fu">&lt;$&gt;</span> [<span class="st">&quot;bob&quot;</span>,<span class="st">&quot;jake&quot;</span>] <span class="fu">&lt;*&gt;</span> [<span class="dv">2</span>,<span class="dv">3</span>] <span class="fu">&lt;*&gt;</span> [<span class="st">&quot;bananas&quot;</span>,<span class="st">&quot;cars&quot;</span>]</a>
<a class="sourceLine" id="cb352-6" data-line-number="6"> <span class="fu">==&gt;</span> [<span class="st">&quot;bob has 2 bananas&quot;</span>,</a>
<a class="sourceLine" id="cb352-7" data-line-number="7"> <span class="st">&quot;bob has 2 cars&quot;</span>,</a>
<a class="sourceLine" id="cb352-8" data-line-number="8"> <span class="st">&quot;bob has 3 bananas&quot;</span>,</a>
<a class="sourceLine" id="cb352-9" data-line-number="9"> <span class="st">&quot;bob has 3 cars&quot;</span>,</a>
<a class="sourceLine" id="cb352-10" data-line-number="10"> <span class="st">&quot;jake has 2 bananas&quot;</span>,</a>
<a class="sourceLine" id="cb352-11" data-line-number="11"> <span class="st">&quot;jake has 2 cars&quot;</span>,</a>
<a class="sourceLine" id="cb352-12" data-line-number="12"> <span class="st">&quot;jake has 3 bananas&quot;</span>,</a>
<a class="sourceLine" id="cb352-13" data-line-number="13"> <span class="st">&quot;jake has 3 cars&quot;</span>]</a></code></pre></div>
<p>What’s going on here? Let’s step through the evaluation. The key is that each <code>&lt;*&gt;</code> partially applies one more argument to the function.</p>
<div class="sourceCode" id="cb353"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb353-1" data-line-number="1"> say <span class="fu">&lt;$&gt;</span> <span class="dt">Just</span> <span class="st">&quot;haskell&quot;</span> <span class="fu">&lt;*&gt;</span> <span class="dt">Just</span> <span class="dv">99</span> <span class="fu">&lt;*&gt;</span> <span class="dt">Just</span> <span class="st">&quot;operators&quot;</span></a>
<a class="sourceLine" id="cb353-2" data-line-number="2"><span class="fu">===</span> ((say <span class="fu">&lt;$&gt;</span> <span class="dt">Just</span> <span class="st">&quot;haskell&quot;</span>) <span class="fu">&lt;*&gt;</span> <span class="dt">Just</span> <span class="dv">99</span>) <span class="fu">&lt;*&gt;</span> <span class="dt">Just</span> <span class="st">&quot;operators&quot;</span></a>
<a class="sourceLine" id="cb353-3" data-line-number="3"><span class="fu">===</span> (fmap say (<span class="dt">Just</span> <span class="st">&quot;haskell&quot;</span>) <span class="fu">&lt;*&gt;</span> <span class="dt">Just</span> <span class="dv">99</span>) <span class="fu">&lt;*&gt;</span> <span class="dt">Just</span> <span class="st">&quot;operators&quot;</span></a>
<a class="sourceLine" id="cb353-4" data-line-number="4"><span class="fu">==&gt;</span> (<span class="dt">Just</span> (say <span class="st">&quot;haskell&quot;</span>) <span class="fu">&lt;*&gt;</span> <span class="dt">Just</span> <span class="dv">99</span>) <span class="fu">&lt;*&gt;</span> <span class="dt">Just</span> <span class="st">&quot;operators&quot;</span></a>
<a class="sourceLine" id="cb353-5" data-line-number="5"><span class="fu">==&gt;</span> <span class="dt">Just</span> (say <span class="st">&quot;haskell&quot;</span> <span class="dv">99</span>) <span class="fu">&lt;*&gt;</span> <span class="dt">Just</span> <span class="st">&quot;operators&quot;</span></a>
<a class="sourceLine" id="cb353-6" data-line-number="6"><span class="fu">==&gt;</span> <span class="dt">Just</span> (say <span class="st">&quot;haskell&quot;</span> <span class="dv">99</span> <span class="st">&quot;operators&quot;</span>)</a>
<a class="sourceLine" id="cb353-7" data-line-number="7"><span class="fu">==&gt;</span> <span class="dt">Just</span> <span class="st">&quot;haskell has 99 operators&quot;</span></a></code></pre></div>
<p>Perhaps looking at the types will make it clearer:</p>
<div class="sourceCode" id="cb354"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb354-1" data-line-number="1">say <span class="fu">&lt;$&gt;</span> <span class="dt">Just</span> <span class="st">&quot;haskell&quot;</span><span class="ot"> ::</span> <span class="dt">Maybe</span> (<span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">String</span>)</a>
<a class="sourceLine" id="cb354-2" data-line-number="2">say <span class="fu">&lt;$&gt;</span> <span class="dt">Just</span> <span class="st">&quot;haskell&quot;</span> <span class="fu">&lt;*&gt;</span> <span class="dt">Just</span> <span class="dv">99</span><span class="ot"> ::</span> <span class="dt">Maybe</span> ( <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">String</span>)</a>
<a class="sourceLine" id="cb354-3" data-line-number="3">say <span class="fu">&lt;$&gt;</span> <span class="dt">Just</span> <span class="st">&quot;haskell&quot;</span> <span class="fu">&lt;*&gt;</span> <span class="dt">Just</span> <span class="dv">99</span> <span class="fu">&lt;*&gt;</span> <span class="dt">Just</span> <span class="st">&quot;operators&quot;</span><span class="ot"> ::</span> <span class="dt">Maybe</span> ( <span class="dt">String</span>)</a></code></pre></div>
<p>The next two operators are a bit simpler:</p>
<div class="sourceCode" id="cb355"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb355-1" data-line-number="1"><span class="ot">(*&gt;) ::</span> <span class="dt">Applicative</span> f <span class="ot">=&gt;</span> f a <span class="ot">-&gt;</span> f b <span class="ot">-&gt;</span> f b</a>
<a class="sourceLine" id="cb355-2" data-line-number="2">x <span class="fu">*&gt;</span> y <span class="fu">=</span> liftA2 (\a b <span class="ot">-&gt;</span> b) x y</a>
<a class="sourceLine" id="cb355-3" data-line-number="3"></a>
<a class="sourceLine" id="cb355-4" data-line-number="4"><span class="ot">(&lt;*) ::</span> <span class="dt">Applicative</span> f <span class="ot">=&gt;</span> f a <span class="ot">-&gt;</span> f b <span class="ot">-&gt;</span> f a</a>
<a class="sourceLine" id="cb355-5" data-line-number="5">x <span class="fu">&lt;*</span> y <span class="fu">=</span> liftA2 (\a b <span class="ot">-&gt;</span> a) x y</a></code></pre></div>
<p>You can compare the types to a more familiar operator:</p>
<div class="sourceCode" id="cb356"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb356-1" data-line-number="1"><span class="ot">(&gt;&gt;) ::</span> <span class="dt">Monad</span> m <span class="ot">=&gt;</span> m a <span class="ot">-&gt;</span> m b <span class="ot">-&gt;</span> m b</a></code></pre></div>
<p>What the operators <code>&lt;*</code> and <code>*&gt;</code> mean is: run both of these operations, but only keep one result. The arrow points to the result that’s kept:</p>
<div class="sourceCode" id="cb357"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb357-1" data-line-number="1"><span class="dt">Just</span> <span class="dv">1</span> <span class="fu">*&gt;</span> <span class="dt">Just</span> <span class="dv">2</span> <span class="fu">==&gt;</span> <span class="dt">Just</span> <span class="dv">2</span></a>
<a class="sourceLine" id="cb357-2" data-line-number="2"><span class="dt">Just</span> <span class="dv">1</span> <span class="fu">&lt;*</span> <span class="dt">Just</span> <span class="dv">2</span> <span class="fu">==&gt;</span> <span class="dt">Just</span> <span class="dv">1</span></a>
<a class="sourceLine" id="cb357-3" data-line-number="3"><span class="dt">Just</span> <span class="dv">1</span> <span class="fu">&lt;*</span> <span class="dt">Nothing</span> <span class="fu">==&gt;</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb357-4" data-line-number="4"><span class="dt">Nothing</span> <span class="fu">&lt;*</span> <span class="dt">Just</span> <span class="dv">2</span> <span class="fu">==&gt;</span> <span class="dt">Nothing</span></a></code></pre></div>
<p>These operators might seem trivial, but they’re useful when combining checks. For example:</p>
<div class="sourceCode" id="cb358"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb358-1" data-line-number="1"><span class="ot">decrease ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> <span class="dt">Int</span></a>
<a class="sourceLine" id="cb358-2" data-line-number="2">decrease i <span class="fu">=</span> <span class="kw">if</span> i<span class="fu">&gt;</span><span class="dv">0</span> <span class="kw">then</span> <span class="dt">Just</span> (i<span class="fu">-</span><span class="dv">1</span>) <span class="kw">else</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb358-3" data-line-number="3"></a>
<a class="sourceLine" id="cb358-4" data-line-number="4"><span class="ot">small ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> <span class="dt">Int</span></a>
<a class="sourceLine" id="cb358-5" data-line-number="5">small i <span class="fu">=</span> <span class="kw">if</span> i<span class="fu">&lt;</span><span class="dv">10</span> <span class="kw">then</span> <span class="dt">Just</span> i <span class="kw">else</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb358-6" data-line-number="6"></a>
<a class="sourceLine" id="cb358-7" data-line-number="7"><span class="ot">decreaseSmall ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> <span class="dt">Int</span></a>
<a class="sourceLine" id="cb358-8" data-line-number="8"><span class="co">-- do what decrease does, but fail if small fails</span></a>
<a class="sourceLine" id="cb358-9" data-line-number="9">decreaseSmall i <span class="fu">=</span> decrease i <span class="fu">&lt;*</span> small i</a></code></pre></div>
<div class="sourceCode" id="cb359"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb359-1" data-line-number="1">decreaseSmall <span class="dv">4</span> <span class="fu">==&gt;</span> <span class="dt">Just</span> <span class="dv">3</span></a>
<a class="sourceLine" id="cb359-2" data-line-number="2">decreaseSmall <span class="dv">0</span> <span class="fu">==&gt;</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb359-3" data-line-number="3">decreaseSmall <span class="dv">11</span> <span class="fu">==&gt;</span> <span class="dt">Nothing</span></a></code></pre></div>
<p>Now that we’ve seen all these operators, we can understand the full definition of <code>Applicative</code>. All the operators have definitions in terms of <code>liftA2</code>, so it’s enought to define <code>liftA2</code> and <code>pure</code> when implementing an <code>Applicative</code> instance.</p>
<div class="sourceCode" id="cb360"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb360-1" data-line-number="1"><span class="kw">class</span> <span class="dt">Functor</span> f <span class="ot">=&gt;</span> <span class="dt">Applicative</span> f <span class="kw">where</span></a>
<a class="sourceLine" id="cb360-2" data-line-number="2"><span class="ot"> pure ::</span> a <span class="ot">-&gt;</span> f a</a>
<a class="sourceLine" id="cb360-3" data-line-number="3"><span class="ot"> liftA2 ::</span> (a <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> c) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> f b <span class="ot">-&gt;</span> f c</a>
<a class="sourceLine" id="cb360-4" data-line-number="4"><span class="ot"> (&lt;*&gt;) ::</span> f (a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> f b</a>
<a class="sourceLine" id="cb360-5" data-line-number="5"><span class="ot"> (*&gt;) ::</span> f a <span class="ot">-&gt;</span> f b <span class="ot">-&gt;</span> f b</a>
<a class="sourceLine" id="cb360-6" data-line-number="6"><span class="ot"> (&lt;*) ::</span> f a <span class="ot">-&gt;</span> f b <span class="ot">-&gt;</span> f a</a></code></pre></div>
<h2 id="the-validation-applicative"><span class="header-section-number">15.4</span> The Validation Applicative</h2>
<p>Let’s look at an Applicative that’s a bit more interesting than Maybe or lists. Often in programming we need to <em>validate</em> some inputs from the user. In these cases it’s useful to gather together all the errors that the input might have. The file <a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Examples/Validation.hs"><code>exercises/Examples/Validation.hs</code></a> implements the <code>Validation</code> datatype:</p>
<div class="sourceCode" id="cb361"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb361-1" data-line-number="1"><span class="kw">data</span> <span class="dt">Validation</span> a <span class="fu">=</span> <span class="dt">Ok</span> a <span class="fu">|</span> <span class="dt">Errors</span> [<span class="dt">String</span>]</a>
<a class="sourceLine" id="cb361-2" data-line-number="2"> <span class="kw">deriving</span> (<span class="dt">Show</span>,<span class="dt">Eq</span>)</a></code></pre></div>
<p>The <code>Applicative</code> instance for <code>Validation</code> works like this:</p>
<div class="sourceCode" id="cb362"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb362-1" data-line-number="1">liftA2 (<span class="fu">+</span>) (<span class="dt">Ok</span> <span class="dv">1</span>) (<span class="dt">Ok</span> <span class="dv">2</span>)</a>
<a class="sourceLine" id="cb362-2" data-line-number="2"> <span class="fu">==&gt;</span> <span class="dt">Ok</span> <span class="dv">3</span></a>
<a class="sourceLine" id="cb362-3" data-line-number="3">liftA2 (<span class="fu">+</span>) (<span class="dt">Errors</span> [<span class="st">&quot;oh no&quot;</span>]) (<span class="dt">Errors</span> [<span class="st">&quot;boom&quot;</span>])</a>
<a class="sourceLine" id="cb362-4" data-line-number="4"> <span class="fu">==&gt;</span> <span class="dt">Errors</span> [<span class="st">&quot;oh no&quot;</span>,<span class="st">&quot;boom&quot;</span>]</a></code></pre></div>
<p>Note how in contrast to the <code>Maybe</code> Applicative, we have many different kinds of failures.</p>
<p>Here’s a worked example that introduces some helpers and then uses them to congratulate somebody on their birthday:</p>
<div class="sourceCode" id="cb363"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb363-1" data-line-number="1"><span class="ot">invalid ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Validation</span> a</a>
<a class="sourceLine" id="cb363-2" data-line-number="2">invalid err <span class="fu">=</span> <span class="dt">Errors</span> [err]</a>
<a class="sourceLine" id="cb363-3" data-line-number="3"></a>
<a class="sourceLine" id="cb363-4" data-line-number="4"><span class="ot">check ::</span> <span class="dt">Bool</span> <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Validation</span> a</a>
<a class="sourceLine" id="cb363-5" data-line-number="5">check b err x</a>
<a class="sourceLine" id="cb363-6" data-line-number="6"> <span class="fu">|</span> b <span class="fu">=</span> pure x</a>
<a class="sourceLine" id="cb363-7" data-line-number="7"> <span class="fu">|</span> otherwise <span class="fu">=</span> invalid err</a>
<a class="sourceLine" id="cb363-8" data-line-number="8"></a>
<a class="sourceLine" id="cb363-9" data-line-number="9"><span class="ot">birthday ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Validation</span> <span class="dt">String</span></a>
<a class="sourceLine" id="cb363-10" data-line-number="10">birthday name age <span class="fu">=</span> liftA2 congratulate checkedName checkedAge</a>
<a class="sourceLine" id="cb363-11" data-line-number="11"> <span class="kw">where</span> checkedName <span class="fu">=</span> check (length name <span class="fu">&lt;</span> <span class="dv">10</span>) <span class="st">&quot;Name too long&quot;</span> name</a>
<a class="sourceLine" id="cb363-12" data-line-number="12"> checkedAge <span class="fu">=</span> check (age <span class="fu">&lt;</span> <span class="dv">99</span>) <span class="st">&quot;Too old&quot;</span> age</a>
<a class="sourceLine" id="cb363-13" data-line-number="13"> congratulate n a <span class="fu">=</span> <span class="st">&quot;Happy &quot;</span><span class="fu">++</span>show a<span class="fu">++</span><span class="st">&quot;th birthday &quot;</span><span class="fu">++</span>n<span class="fu">++</span><span class="st">&quot;!&quot;</span></a></code></pre></div>
<div class="sourceCode" id="cb364"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb364-1" data-line-number="1">birthday <span class="st">&quot;Guy&quot;</span> <span class="dv">31</span></a>
<a class="sourceLine" id="cb364-2" data-line-number="2"> <span class="fu">==&gt;</span> <span class="dt">Ok</span> <span class="st">&quot;Happy 31th birthday Guy!&quot;</span></a>
<a class="sourceLine" id="cb364-3" data-line-number="3">birthday <span class="st">&quot;Guybrush Threepwood&quot;</span> <span class="dv">31</span></a>
<a class="sourceLine" id="cb364-4" data-line-number="4"> <span class="fu">==&gt;</span> <span class="dt">Errors</span> [<span class="st">&quot;Name too long&quot;</span>]</a>
<a class="sourceLine" id="cb364-5" data-line-number="5">birthday <span class="st">&quot;Yog-sothoth&quot;</span> <span class="dv">10000</span></a>
<a class="sourceLine" id="cb364-6" data-line-number="6"> <span class="fu">==&gt;</span> <span class="dt">Errors</span> [<span class="st">&quot;Name too long&quot;</span>,<span class="st">&quot;Too old&quot;</span>]</a></code></pre></div>
<p>Oh right, here are the <code>Functor</code> and <code>Applicative</code> instances for <code>Validation</code>:</p>
<div class="sourceCode" id="cb365"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb365-1" data-line-number="1"><span class="kw">instance</span> <span class="dt">Functor</span> <span class="dt">Validation</span> <span class="kw">where</span></a>
<a class="sourceLine" id="cb365-2" data-line-number="2"> fmap f (<span class="dt">Ok</span> x) <span class="fu">=</span> <span class="dt">Ok</span> (f x)</a>
<a class="sourceLine" id="cb365-3" data-line-number="3"> fmap _ (<span class="dt">Errors</span> e) <span class="fu">=</span> <span class="dt">Errors</span> e</a>
<a class="sourceLine" id="cb365-4" data-line-number="4"></a>
<a class="sourceLine" id="cb365-5" data-line-number="5"><span class="kw">instance</span> <span class="dt">Applicative</span> <span class="dt">Validation</span> <span class="kw">where</span></a>
<a class="sourceLine" id="cb365-6" data-line-number="6"> pure x <span class="fu">=</span> <span class="dt">Ok</span> x</a>
<a class="sourceLine" id="cb365-7" data-line-number="7"> liftA2 f (<span class="dt">Ok</span> x) (<span class="dt">Ok</span> y) <span class="fu">=</span> <span class="dt">Ok</span> (f x y)</a>
<a class="sourceLine" id="cb365-8" data-line-number="8"> liftA2 f (<span class="dt">Errors</span> e1) (<span class="dt">Ok</span> y) <span class="fu">=</span> <span class="dt">Errors</span> e1</a>
<a class="sourceLine" id="cb365-9" data-line-number="9"> liftA2 f (<span class="dt">Ok</span> x) (<span class="dt">Errors</span> e2) <span class="fu">=</span> <span class="dt">Errors</span> e2</a>
<a class="sourceLine" id="cb365-10" data-line-number="10"> liftA2 f (<span class="dt">Errors</span> e1) (<span class="dt">Errors</span> e2) <span class="fu">=</span> <span class="dt">Errors</span> (e1<span class="fu">++</span>e2)</a></code></pre></div>
<p>The definition of <code>liftA2</code> for <code>Validation</code> shows that the errors are collected together left-to-right. This can be seen in the example above where the expression <code>liftA2 congratulate checkedName checkedAge</code> outputs the error (<code>&quot;Name too long&quot;</code>) from <code>checkedName</code> first, and the error (<code>&quot;Too old&quot;</code>) from <code>checkedAge</code> last.</p>
<p>PS. The same sort of idea has been implemented in the <a href="https://hackage.haskell.org/package/validation">validation</a> and <a href="https://hackage.haskell.org/package/either">either</a> libraries.</p>
<!-- TODO other applicatives: IO, ? -->
<h2 id="validating-lists-traverse"><span class="header-section-number">15.5</span> Validating Lists: <code>traverse</code></h2>
<p>So far we’ve dealt with fixed-size things and Applicatives: we’ve applied a function of two or three arguments to some things. What if we have an arbitrary amount of inputs? What if we need to validate a list?</p>
<p>Let’s look at some ways to implement a function like this:</p>
<div class="sourceCode" id="cb366"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb366-1" data-line-number="1">allPositive [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
<a class="sourceLine" id="cb366-2" data-line-number="2"> <span class="fu">==&gt;</span> <span class="dt">Ok</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
<a class="sourceLine" id="cb366-3" data-line-number="3">allPositive [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="fu">-</span><span class="dv">4</span>]</a>
<a class="sourceLine" id="cb366-4" data-line-number="4"> <span class="fu">==&gt;</span> <span class="dt">Errors</span> [<span class="st">&quot;Not positive: -4&quot;</span>]</a>
<a class="sourceLine" id="cb366-5" data-line-number="5">allPositive [<span class="dv">1</span>,<span class="fu">-</span><span class="dv">2</span>,<span class="dv">3</span>,<span class="fu">-</span><span class="dv">4</span>]</a>
<a class="sourceLine" id="cb366-6" data-line-number="6"> <span class="fu">==&gt;</span> <span class="dt">Errors</span> [<span class="st">&quot;Not positive: -2&quot;</span>,<span class="st">&quot;Not positive: -4&quot;</span>]</a></code></pre></div>
<p>As always, when working with lists, pattern matching and recursion are usually the way to go. Here’s a recursive solution:</p>
<div class="sourceCode" id="cb367"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb367-1" data-line-number="1"><span class="ot">allPositive ::</span> [<span class="dt">Int</span>] <span class="ot">-&gt;</span> <span class="dt">Validation</span> [<span class="dt">Int</span>]</a>
<a class="sourceLine" id="cb367-2" data-line-number="2">allPositive [] <span class="fu">=</span> <span class="dt">Ok</span> []</a>
<a class="sourceLine" id="cb367-3" data-line-number="3">allPositive (x<span class="fu">:</span>xs) <span class="fu">=</span> liftA2 (<span class="fu">:</span>) checkThis checkRest</a>
<a class="sourceLine" id="cb367-4" data-line-number="4"> <span class="kw">where</span> checkThis <span class="fu">=</span> check (x<span class="fu">&gt;=</span><span class="dv">0</span>) (<span class="st">&quot;Not positive: &quot;</span><span class="fu">++</span>show x) x</a>
<a class="sourceLine" id="cb367-5" data-line-number="5"> checkRest <span class="fu">=</span> allPositive xs</a></code></pre></div>
<p>It’s a bit of a chore to always spell out a recursion like this. If we were working in a <code>Monad</code> we could just use a helper like <code>mapM</code>:</p>
<div class="sourceCode" id="cb368"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb368-1" data-line-number="1">mapM (\x <span class="ot">-&gt;</span> <span class="kw">if</span> x<span class="fu">&gt;=</span><span class="dv">0</span> <span class="kw">then</span> <span class="dt">Just</span> x <span class="kw">else</span> <span class="dt">Nothing</span>) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
<a class="sourceLine" id="cb368-2" data-line-number="2"> <span class="fu">==&gt;</span> <span class="dt">Just</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
<a class="sourceLine" id="cb368-3" data-line-number="3">mapM (\x <span class="ot">-&gt;</span> <span class="kw">if</span> x<span class="fu">&gt;=</span><span class="dv">0</span> <span class="kw">then</span> <span class="dt">Just</span> x <span class="kw">else</span> <span class="dt">Nothing</span>) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="fu">-</span><span class="dv">4</span>]</a>
<a class="sourceLine" id="cb368-4" data-line-number="4"> <span class="fu">==&gt;</span> <span class="dt">Nothing</span></a></code></pre></div>
<p>The equivalent of <code>mapM</code> for <code>Applicative</code> is called <code>traverse</code>. It’s a member of the type class <code>Traversable</code>:</p>
<div class="sourceCode" id="cb369"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb369-1" data-line-number="1">traverse<span class="ot"> ::</span> (<span class="dt">Traversable</span> t, <span class="dt">Applicative</span> f) <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> f b) <span class="ot">-&gt;</span> t a <span class="ot">-&gt;</span> f (t b)</a></code></pre></div>
<p>That’s one heck of a type signature, so let’s simplify it a bit. Lists are <code>Traversable</code>, so we can specialize this type into:</p>
<div class="sourceCode" id="cb370"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb370-1" data-line-number="1">traverse<span class="ot"> ::</span> <span class="dt">Applicative</span> f <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> f b) <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> f [b]</a></code></pre></div>
<p>That looks like what we need! For Applicatives that are also Monads, <code>traverse</code> is just another name for <code>mapM</code>:</p>
<div class="sourceCode" id="cb371"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb371-1" data-line-number="1">traverse (\x <span class="ot">-&gt;</span> <span class="kw">if</span> x<span class="fu">&gt;=</span><span class="dv">0</span> <span class="kw">then</span> <span class="dt">Just</span> x <span class="kw">else</span> <span class="dt">Nothing</span>) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
<a class="sourceLine" id="cb371-2" data-line-number="2"> <span class="fu">==&gt;</span> <span class="dt">Just</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
<a class="sourceLine" id="cb371-3" data-line-number="3">traverse (\x <span class="ot">-&gt;</span> <span class="kw">if</span> x<span class="fu">&gt;=</span><span class="dv">0</span> <span class="kw">then</span> <span class="dt">Just</span> x <span class="kw">else</span> <span class="dt">Nothing</span>) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="fu">-</span><span class="dv">4</span>]</a>
<a class="sourceLine" id="cb371-4" data-line-number="4"> <span class="fu">==&gt;</span> <span class="dt">Nothing</span></a></code></pre></div>
<p>But for our <code>Validation</code>, which isn’t a <code>Monad</code>, <code>traverse</code> is exactly what we want:</p>
<div class="sourceCode" id="cb372"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb372-1" data-line-number="1"><span class="ot">allPositive ::</span> [<span class="dt">Int</span>] <span class="ot">-&gt;</span> <span class="dt">Validation</span> [<span class="dt">Int</span>]</a>
<a class="sourceLine" id="cb372-2" data-line-number="2">allPositive xs <span class="fu">=</span> traverse checkNumber xs</a>
<a class="sourceLine" id="cb372-3" data-line-number="3"> <span class="kw">where</span> checkNumber x <span class="fu">=</span> check (x<span class="fu">&gt;=</span><span class="dv">0</span>) (<span class="st">&quot;Not positive: &quot;</span><span class="fu">++</span>show x) x</a></code></pre></div>
<div class="sourceCode" id="cb373"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb373-1" data-line-number="1">allPositive [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
<a class="sourceLine" id="cb373-2" data-line-number="2"> <span class="fu">==&gt;</span> <span class="dt">Ok</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
<a class="sourceLine" id="cb373-3" data-line-number="3">allPositive [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="fu">-</span><span class="dv">4</span>]</a>
<a class="sourceLine" id="cb373-4" data-line-number="4"> <span class="fu">==&gt;</span> <span class="dt">Errors</span> [<span class="st">&quot;Not positive: -4&quot;</span>]</a>
<a class="sourceLine" id="cb373-5" data-line-number="5">allPositive [<span class="dv">1</span>,<span class="fu">-</span><span class="dv">2</span>,<span class="dv">3</span>,<span class="fu">-</span><span class="dv">4</span>]</a>
<a class="sourceLine" id="cb373-6" data-line-number="6"> <span class="fu">==&gt;</span> <span class="dt">Errors</span> [<span class="st">&quot;Not positive: -2&quot;</span>,<span class="st">&quot;Not positive: -4&quot;</span>]</a></code></pre></div>
<p>Note how <code>traverse</code> for <code>Validation</code> collects all the errors together, in the order they occur in the original list.</p>
<p>PS. In fact, <code>Validation</code> is one of the few examples of an <code>Applicative</code> that can’t be a <code>Monad</code>. Can you figure out why?</p>
<!-- TODO `traverse_`? -->
<h2 id="sidenote-traversable"><span class="header-section-number">15.6</span> Sidenote: <code>Traversable</code></h2>
<p>So what things are <code>Traversable</code>? Many familiar structures. Here are some examples:</p>
<div class="sourceCode" id="cb374"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb374-1" data-line-number="1"><span class="ot">decrease ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> <span class="dt">Int</span></a>
<a class="sourceLine" id="cb374-2" data-line-number="2">decrease i <span class="fu">=</span> <span class="kw">if</span> i<span class="fu">&gt;</span><span class="dv">0</span> <span class="kw">then</span> <span class="dt">Just</span> (i<span class="fu">-</span><span class="dv">1</span>) <span class="kw">else</span> <span class="dt">Nothing</span></a></code></pre></div>
<div class="sourceCode" id="cb375"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb375-1" data-line-number="1"><span class="co">-- Lists are Traversable</span></a>
<a class="sourceLine" id="cb375-2" data-line-number="2">traverse decrease [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="fu">==&gt;</span> <span class="dt">Just</span> [<span class="dv">0</span>,<span class="dv">1</span>,<span class="dv">2</span>]</a>
<a class="sourceLine" id="cb375-3" data-line-number="3">traverse decrease [<span class="dv">1</span>,<span class="dv">0</span>,<span class="dv">3</span>] <span class="fu">==&gt;</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb375-4" data-line-number="4"></a>
<a class="sourceLine" id="cb375-5" data-line-number="5"><span class="co">-- Arrays are Traversable</span></a>
<a class="sourceLine" id="cb375-6" data-line-number="6">traverse decrease (array (<span class="dv">1</span>,<span class="dv">3</span>) [(<span class="dv">1</span>,<span class="dv">10</span>),(<span class="dv">2</span>,<span class="dv">11</span>),(<span class="dv">3</span>,<span class="dv">12</span>)])</a>
<a class="sourceLine" id="cb375-7" data-line-number="7"> <span class="fu">==&gt;</span> <span class="dt">Just</span> (array (<span class="dv">1</span>,<span class="dv">3</span>) [(<span class="dv">1</span>,<span class="dv">9</span>),(<span class="dv">2</span>,<span class="dv">10</span>),(<span class="dv">3</span>,<span class="dv">11</span>)])</a>
<a class="sourceLine" id="cb375-8" data-line-number="8"></a>
<a class="sourceLine" id="cb375-9" data-line-number="9"><span class="co">-- Maps are Traversable</span></a>
<a class="sourceLine" id="cb375-10" data-line-number="10">traverse decrease (M.fromList [(<span class="st">&quot;a&quot;</span>,<span class="dv">1</span>),(<span class="st">&quot;b&quot;</span>,<span class="dv">2</span>)])</a>
<a class="sourceLine" id="cb375-11" data-line-number="11"> <span class="fu">==&gt;</span> <span class="dt">Just</span> (M.fromList [(<span class="st">&quot;a&quot;</span>,<span class="dv">0</span>),(<span class="st">&quot;b&quot;</span>,<span class="dv">1</span>)])</a>
<a class="sourceLine" id="cb375-12" data-line-number="12">traverse decrease (M.fromList [(<span class="st">&quot;a&quot;</span>,<span class="dv">1</span>),(<span class="st">&quot;b&quot;</span>,<span class="dv">0</span>)])</a>
<a class="sourceLine" id="cb375-13" data-line-number="13"> <span class="fu">==&gt;</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb375-14" data-line-number="14"></a>
<a class="sourceLine" id="cb375-15" data-line-number="15"><span class="co">-- Either is Traversable</span></a>
<a class="sourceLine" id="cb375-16" data-line-number="16">traverse decrease (<span class="dt">Left</span> <span class="st">&quot;abc&quot;</span>) <span class="fu">==&gt;</span> <span class="dt">Just</span> (<span class="dt">Left</span> <span class="st">&quot;abc&quot;</span>)</a>
<a class="sourceLine" id="cb375-17" data-line-number="17">traverse decrease (<span class="dt">Right</span> <span class="dv">3</span>) <span class="fu">==&gt;</span> <span class="dt">Just</span> (<span class="dt">Right</span> <span class="dv">2</span>)</a>
<a class="sourceLine" id="cb375-18" data-line-number="18">traverse decrease (<span class="dt">Right</span> <span class="dv">0</span>) <span class="fu">==&gt;</span> <span class="dt">Nothing</span></a></code></pre></div>
<p>So <code>Traversable</code> is a type class for all sorts of containers, kind of like <code>Foldable</code>. Indeed, if you look at the definition, <code>Traversable</code> is a subclass of <code>Foldable</code>. It also turns out that <code>traverse</code> and <code>mapM</code> are methods of the class!</p>
<div class="sourceCode" id="cb376"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb376-1" data-line-number="1"><span class="kw">class</span> (<span class="dt">Functor</span> t, <span class="dt">Foldable</span> t) <span class="ot">=&gt;</span> <span class="dt">Traversable</span> t <span class="kw">where</span></a>
<a class="sourceLine" id="cb376-2" data-line-number="2"><span class="ot"> traverse ::</span> <span class="dt">Applicative</span> f <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> f b) <span class="ot">-&gt;</span> t a <span class="ot">-&gt;</span> f (t b)</a>
<a class="sourceLine" id="cb376-3" data-line-number="3"><span class="ot"> mapM ::</span> <span class="dt">Monad</span> m <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> m b) <span class="ot">-&gt;</span> t a <span class="ot">-&gt;</span> m (t b)</a></code></pre></div>
<p>It can be hard to keep the types straight here. Let’s go back to the type of <code>traverse</code>:</p>
<div class="sourceCode" id="cb377"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb377-1" data-line-number="1">traverse<span class="ot"> ::</span> (<span class="dt">Traversable</span> t, <span class="dt">Applicative</span> f) <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> f b) <span class="ot">-&gt;</span> t a <span class="ot">-&gt;</span> f (t b)</a></code></pre></div>
<p>Here we have two functors: <code>t</code> and <code>f</code>. The <code>t</code> functor is also a <code>Foldable</code> and a <code>Traversable</code> and the <code>f</code> functor is also an <code>Applicative</code>. The <code>traverse</code> function lets us run <code>f</code>-operations inside a <code>t</code>-container.</p>
<p>Don’t worry if that feels abstract. In practice, you pretty much always use <code>traverse</code> on lists.</p>
<h2 id="dealing-with-failure-alternative"><span class="header-section-number">15.7</span> Dealing with Failure: <code>Alternative</code></h2>
<p>If you play around with applicatives a bit you’ll start to notice some limits to their power. For example, when writing parsers like we did in the <code>parseMoney</code> example, it would be nice to be able to try some a couple of different parsers and take any non-failure result. This is easy enough to write for a concrete Applicative like <code>Maybe</code>, as can be seen below.</p>
<div class="sourceCode" id="cb378"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb378-1" data-line-number="1"><span class="kw">data</span> <span class="dt">Answer</span> <span class="fu">=</span> <span class="dt">Yes</span> <span class="fu">|</span> <span class="dt">No</span></a>
<a class="sourceLine" id="cb378-2" data-line-number="2"> <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</a>
<a class="sourceLine" id="cb378-3" data-line-number="3"></a>
<a class="sourceLine" id="cb378-4" data-line-number="4"><span class="ot">parseYes ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> <span class="dt">Answer</span></a>
<a class="sourceLine" id="cb378-5" data-line-number="5">parseYes <span class="st">&quot;y&quot;</span> <span class="fu">=</span> <span class="dt">Just</span> <span class="dt">Yes</span></a>
<a class="sourceLine" id="cb378-6" data-line-number="6">parseYes <span class="st">&quot;yes&quot;</span> <span class="fu">=</span> <span class="dt">Just</span> <span class="dt">Yes</span></a>
<a class="sourceLine" id="cb378-7" data-line-number="7">parseYes <span class="st">&quot;maybe&quot;</span> <span class="fu">=</span> <span class="dt">Just</span> <span class="dt">Yes</span></a>
<a class="sourceLine" id="cb378-8" data-line-number="8">parseYes _ <span class="fu">=</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb378-9" data-line-number="9"></a>
<a class="sourceLine" id="cb378-10" data-line-number="10"><span class="ot">parseNo ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> <span class="dt">Answer</span></a>
<a class="sourceLine" id="cb378-11" data-line-number="11">parseNo <span class="st">&quot;n&quot;</span> <span class="fu">=</span> <span class="dt">Just</span> <span class="dt">No</span></a>
<a class="sourceLine" id="cb378-12" data-line-number="12">parseNo <span class="st">&quot;no&quot;</span> <span class="fu">=</span> <span class="dt">Just</span> <span class="dt">No</span></a>
<a class="sourceLine" id="cb378-13" data-line-number="13">parseNo <span class="st">&quot;maybe&quot;</span> <span class="fu">=</span> <span class="dt">Just</span> <span class="dt">No</span></a>
<a class="sourceLine" id="cb378-14" data-line-number="14">parseNo _ <span class="fu">=</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb378-15" data-line-number="15"></a>
<a class="sourceLine" id="cb378-16" data-line-number="16"><span class="ot">eitherOf ::</span> <span class="dt">Maybe</span> x <span class="ot">-&gt;</span> <span class="dt">Maybe</span> x <span class="ot">-&gt;</span> <span class="dt">Maybe</span> x</a>
<a class="sourceLine" id="cb378-17" data-line-number="17">eitherOf (<span class="dt">Just</span> x) _ <span class="fu">=</span> <span class="dt">Just</span> x</a>
<a class="sourceLine" id="cb378-18" data-line-number="18">eitherOf <span class="dt">Nothing</span> mx <span class="fu">=</span> mx</a>
<a class="sourceLine" id="cb378-19" data-line-number="19"></a>
<a class="sourceLine" id="cb378-20" data-line-number="20"><span class="ot">parseAnswer ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> <span class="dt">Answer</span></a>
<a class="sourceLine" id="cb378-21" data-line-number="21"><span class="co">-- prefer positive answers!</span></a>
<a class="sourceLine" id="cb378-22" data-line-number="22">parseAnswer s <span class="fu">=</span> eitherOf (parseYes s) (parseNo s)</a></code></pre></div>
<div class="sourceCode" id="cb379"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb379-1" data-line-number="1">parseAnswer <span class="st">&quot;yes&quot;</span> <span class="fu">==&gt;</span> <span class="dt">Just</span> <span class="dt">Yes</span></a>
<a class="sourceLine" id="cb379-2" data-line-number="2">parseAnswer <span class="st">&quot;y&quot;</span> <span class="fu">==&gt;</span> <span class="dt">Just</span> <span class="dt">Yes</span></a>
<a class="sourceLine" id="cb379-3" data-line-number="3">parseAnswer <span class="st">&quot;n&quot;</span> <span class="fu">==&gt;</span> <span class="dt">Just</span> <span class="dt">No</span></a>
<a class="sourceLine" id="cb379-4" data-line-number="4">parseAnswer <span class="st">&quot;maybe&quot;</span> <span class="fu">==&gt;</span> <span class="dt">Just</span> <span class="dt">Yes</span></a>
<a class="sourceLine" id="cb379-5" data-line-number="5">parseAnswer <span class="st">&quot;x&quot;</span> <span class="fu">==&gt;</span> <span class="dt">Nothing</span></a></code></pre></div>
<p>How could we generalize <code>eitherOf</code>? We can’t give it the type <code>Applicative f =&gt; f x -&gt; f x -&gt; f x</code> because then the implementation would need to be effectively something like <code>eitherOf a b = liftA2 something a b</code>, but then <code>eitherOf Nothing (Just x)</code> would be <code>Nothing</code> (since that’s how the instance Applicative instance works)!</p>
<p>It turns out we need a new type class: <code>Alternative</code>. An Alternative adds two operations to Applicative: <code>empty</code> means no results, and <code>&lt;|&gt;</code> means combining results.</p>
<div class="sourceCode" id="cb380"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb380-1" data-line-number="1"><span class="kw">class</span> <span class="dt">Applicative</span> f <span class="ot">=&gt;</span> <span class="dt">Alternative</span> f <span class="kw">where</span></a>
<a class="sourceLine" id="cb380-2" data-line-number="2"><span class="ot"> empty ::</span> f a</a>
<a class="sourceLine" id="cb380-3" data-line-number="3"><span class="ot"> (&lt;|&gt;) ::</span> f a <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> f a</a>
<a class="sourceLine" id="cb380-4" data-line-number="4"> <span class="co">-- some other operations omitted</span></a></code></pre></div>
<p>Now we can rewrite our parsing code using general operations:</p>
<div class="sourceCode" id="cb381"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb381-1" data-line-number="1"><span class="kw">data</span> <span class="dt">Answer</span> <span class="fu">=</span> <span class="dt">Yes</span> <span class="fu">|</span> <span class="dt">No</span></a>
<a class="sourceLine" id="cb381-2" data-line-number="2"> <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</a>
<a class="sourceLine" id="cb381-3" data-line-number="3"></a>
<a class="sourceLine" id="cb381-4" data-line-number="4"><span class="ot">parseYes ::</span> <span class="dt">Alternative</span> f <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> f <span class="dt">Answer</span></a>
<a class="sourceLine" id="cb381-5" data-line-number="5">parseYes <span class="st">&quot;y&quot;</span> <span class="fu">=</span> pure <span class="dt">Yes</span></a>
<a class="sourceLine" id="cb381-6" data-line-number="6">parseYes <span class="st">&quot;yes&quot;</span> <span class="fu">=</span> pure <span class="dt">Yes</span></a>
<a class="sourceLine" id="cb381-7" data-line-number="7">parseYes <span class="st">&quot;maybe&quot;</span> <span class="fu">=</span> pure <span class="dt">Yes</span></a>
<a class="sourceLine" id="cb381-8" data-line-number="8">parseYes _ <span class="fu">=</span> empty</a>
<a class="sourceLine" id="cb381-9" data-line-number="9"></a>
<a class="sourceLine" id="cb381-10" data-line-number="10"><span class="ot">parseNo ::</span> <span class="dt">Alternative</span> f <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> f <span class="dt">Answer</span></a>
<a class="sourceLine" id="cb381-11" data-line-number="11">parseNo <span class="st">&quot;n&quot;</span> <span class="fu">=</span> pure <span class="dt">No</span></a>
<a class="sourceLine" id="cb381-12" data-line-number="12">parseNo <span class="st">&quot;no&quot;</span> <span class="fu">=</span> pure <span class="dt">No</span></a>
<a class="sourceLine" id="cb381-13" data-line-number="13">parseNo <span class="st">&quot;maybe&quot;</span> <span class="fu">=</span> pure <span class="dt">No</span></a>
<a class="sourceLine" id="cb381-14" data-line-number="14">parseNo _ <span class="fu">=</span> empty</a>
<a class="sourceLine" id="cb381-15" data-line-number="15"></a>
<a class="sourceLine" id="cb381-16" data-line-number="16"><span class="ot">parseAnswer ::</span> <span class="dt">Alternative</span> f <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> f <span class="dt">Answer</span></a>
<a class="sourceLine" id="cb381-17" data-line-number="17">parseAnswer s <span class="fu">=</span> parseYes s <span class="fu">&lt;|&gt;</span> parseNo s</a></code></pre></div>
<p>We can also pick which <code>Alternative</code> we run our parser in to get different behaviours. <code>Maybe</code> gives us only one result, while <code>[]</code> gives us all possible results.</p>
<div class="sourceCode" id="cb382"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb382-1" data-line-number="1"><span class="fu">&gt;</span> parseAnswer <span class="st">&quot;yes&quot;</span><span class="ot"> ::</span> <span class="dt">Maybe</span> <span class="dt">Answer</span></a>
<a class="sourceLine" id="cb382-2" data-line-number="2"><span class="dt">Just</span> <span class="dt">Yes</span></a>
<a class="sourceLine" id="cb382-3" data-line-number="3"><span class="fu">&gt;</span> parseAnswer <span class="st">&quot;maybe&quot;</span><span class="ot"> ::</span> <span class="dt">Maybe</span> <span class="dt">Answer</span></a>
<a class="sourceLine" id="cb382-4" data-line-number="4"><span class="dt">Just</span> <span class="dt">Yes</span></a>
<a class="sourceLine" id="cb382-5" data-line-number="5"><span class="fu">&gt;</span> parseAnswer <span class="st">&quot;yes&quot;</span><span class="ot"> ::</span> [<span class="dt">Answer</span>]</a>
<a class="sourceLine" id="cb382-6" data-line-number="6">[<span class="dt">Yes</span>]</a>
<a class="sourceLine" id="cb382-7" data-line-number="7"><span class="fu">&gt;</span> parseAnswer <span class="st">&quot;maybe&quot;</span><span class="ot"> ::</span> [<span class="dt">Answer</span>]</a>
<a class="sourceLine" id="cb382-8" data-line-number="8">[<span class="dt">Yes</span>,<span class="dt">No</span>]</a></code></pre></div>
<p>The <code>Alternative</code> instances for <code>[]</code> and <code>Maybe</code> are unsurprising:</p>
<div class="sourceCode" id="cb383"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb383-1" data-line-number="1"><span class="kw">instance</span> <span class="dt">Alternative</span> [] <span class="kw">where</span></a>
<a class="sourceLine" id="cb383-2" data-line-number="2"> empty <span class="fu">=</span> []</a>
<a class="sourceLine" id="cb383-3" data-line-number="3"> (<span class="fu">&lt;|&gt;</span>) <span class="fu">=</span> (<span class="fu">++</span>)</a>
<a class="sourceLine" id="cb383-4" data-line-number="4"></a>
<a class="sourceLine" id="cb383-5" data-line-number="5"><span class="kw">instance</span> <span class="dt">Alternative</span> <span class="dt">Maybe</span> <span class="kw">where</span></a>
<a class="sourceLine" id="cb383-6" data-line-number="6"> empty <span class="fu">=</span> <span class="dt">Nothing</span></a>
<a class="sourceLine" id="cb383-7" data-line-number="7"> <span class="dt">Just</span> x <span class="fu">&lt;|&gt;</span> _ <span class="fu">=</span> <span class="dt">Just</span> x</a>
<a class="sourceLine" id="cb383-8" data-line-number="8"> <span class="dt">Nothing</span> <span class="fu">&lt;|&gt;</span> mx <span class="fu">=</span> mx</a></code></pre></div>
<p>The <code>Validation</code> type is also an <code>Alternative</code>. The instance collects together all error messages, just like the <code>Applicative</code> instance did.</p>
<div class="sourceCode" id="cb384"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb384-1" data-line-number="1"><span class="kw">instance</span> <span class="dt">Alternative</span> <span class="dt">Validation</span> <span class="kw">where</span></a>
<a class="sourceLine" id="cb384-2" data-line-number="2"> empty <span class="fu">=</span> <span class="dt">Errors</span> []</a>
<a class="sourceLine" id="cb384-3" data-line-number="3"> <span class="dt">Ok</span> x <span class="fu">&lt;|&gt;</span> _ <span class="fu">=</span> <span class="dt">Ok</span> x</a>
<a class="sourceLine" id="cb384-4" data-line-number="4"> <span class="dt">Errors</span> e1 <span class="fu">&lt;|&gt;</span> <span class="dt">Ok</span> y <span class="fu">=</span> <span class="dt">Ok</span> y</a>
<a class="sourceLine" id="cb384-5" data-line-number="5"> <span class="dt">Errors</span> e1 <span class="fu">&lt;|&gt;</span> <span class="dt">Errors</span> e2 <span class="fu">=</span> <span class="dt">Errors</span> (e1<span class="fu">++</span>e2)</a></code></pre></div>
<p>Here’s a final example: validating contact information, which is either a phone number or an email address.</p>
<div class="sourceCode" id="cb385"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb385-1" data-line-number="1"><span class="kw">data</span> <span class="dt">ContactInfo</span> <span class="fu">=</span> <span class="dt">Email</span> <span class="dt">String</span> <span class="fu">|</span> <span class="dt">Phone</span> <span class="dt">String</span></a>
<a class="sourceLine" id="cb385-2" data-line-number="2"> <span class="kw">deriving</span> <span class="dt">Show</span></a>
<a class="sourceLine" id="cb385-3" data-line-number="3"></a>
<a class="sourceLine" id="cb385-4" data-line-number="4"><span class="ot">validateEmail ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Validation</span> <span class="dt">ContactInfo</span></a>
<a class="sourceLine" id="cb385-5" data-line-number="5">validateEmail s <span class="fu">=</span> check (elem <span class="ch">&#39;@&#39;</span> s) <span class="st">&quot;Not an email: should contain a @&quot;</span> (<span class="dt">Email</span> s)</a>
<a class="sourceLine" id="cb385-6" data-line-number="6"></a>
<a class="sourceLine" id="cb385-7" data-line-number="7"><span class="ot">checkLength ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Validation</span> <span class="dt">ContactInfo</span></a>
<a class="sourceLine" id="cb385-8" data-line-number="8">checkLength s <span class="fu">=</span> check (length s <span class="fu">&lt;=</span> <span class="dv">10</span>) <span class="st">&quot;Not a phone number: should be at most 10 digits&quot;</span> (<span class="dt">Phone</span> s)</a>
<a class="sourceLine" id="cb385-9" data-line-number="9"></a>
<a class="sourceLine" id="cb385-10" data-line-number="10"><span class="ot">checkDigits ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Validation</span> <span class="dt">ContactInfo</span></a>
<a class="sourceLine" id="cb385-11" data-line-number="11">checkDigits s <span class="fu">=</span> check (all isDigit s) <span class="st">&quot;Not a phone number: should be all numbers&quot;</span> (<span class="dt">Phone</span> s)</a>
<a class="sourceLine" id="cb385-12" data-line-number="12"></a>
<a class="sourceLine" id="cb385-13" data-line-number="13"><span class="ot">validatePhone ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Validation</span> <span class="dt">ContactInfo</span></a>
<a class="sourceLine" id="cb385-14" data-line-number="14">validatePhone s <span class="fu">=</span> checkDigits s <span class="fu">*&gt;</span> checkLength s</a>
<a class="sourceLine" id="cb385-15" data-line-number="15"></a>
<a class="sourceLine" id="cb385-16" data-line-number="16"><span class="ot">validateContactInfo ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Validation</span> <span class="dt">ContactInfo</span></a>
<a class="sourceLine" id="cb385-17" data-line-number="17">validateContactInfo s <span class="fu">=</span> validateEmail s <span class="fu">&lt;|&gt;</span> validatePhone s</a></code></pre></div>
<div class="sourceCode" id="cb386"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb386-1" data-line-number="1">validateContactInfo <span class="st">&quot;user@example.com&quot;</span></a>
<a class="sourceLine" id="cb386-2" data-line-number="2"> <span class="fu">==&gt;</span> <span class="dt">Ok</span> (<span class="dt">Email</span> <span class="st">&quot;user@example.com&quot;</span>)</a>
<a class="sourceLine" id="cb386-3" data-line-number="3">validateContactInfo <span class="st">&quot;01234&quot;</span></a>
<a class="sourceLine" id="cb386-4" data-line-number="4"> <span class="fu">==&gt;</span> <span class="dt">Ok</span> (<span class="dt">Phone</span> <span class="st">&quot;01234&quot;</span>)</a>
<a class="sourceLine" id="cb386-5" data-line-number="5">validateContactInfo <span class="st">&quot;01234567890&quot;</span></a>
<a class="sourceLine" id="cb386-6" data-line-number="6"> <span class="fu">==&gt;</span> <span class="dt">Errors</span> [<span class="st">&quot;Not an email: should contain a @&quot;</span>,<span class="st">&quot;Not a phone number: should be at most 10 digits&quot;</span>]</a>
<a class="sourceLine" id="cb386-7" data-line-number="7">validateContactInfo <span class="st">&quot;01234567890x&quot;</span></a>
<a class="sourceLine" id="cb386-8" data-line-number="8"> <span class="fu">==&gt;</span> <span class="dt">Errors</span> [<span class="st">&quot;Not an email: should contain a @&quot;</span>,</a>
<a class="sourceLine" id="cb386-9" data-line-number="9"> <span class="st">&quot;Not a phone number: should be all numbers&quot;</span>,</a>
<a class="sourceLine" id="cb386-10" data-line-number="10"> <span class="st">&quot;Not a phone number: should be at most 10 digits&quot;</span>]</a>
<a class="sourceLine" id="cb386-11" data-line-number="11">validateContactInfo <span class="st">&quot;x&quot;</span></a>
<a class="sourceLine" id="cb386-12" data-line-number="12"> <span class="fu">==&gt;</span> <span class="dt">Errors</span> [<span class="st">&quot;Not an email: should contain a @&quot;</span>,</a>
<a class="sourceLine" id="cb386-13" data-line-number="13"> <span class="st">&quot;Not a phone number: should be all numbers&quot;</span>]</a></code></pre></div>
<p>Note how here, just like in previous examples, the errors are collected left-to-right: the errors from <code>validateEmail</code> come before the errors from <code>validatePhone</code>. The error from <code>checkDigits</code> comes before the error from <code>checkLength</code>.</p>
<!--
TODO compare to `Monoid`?
TODO another example
TODO explain `some` and `many`
-->
<h2 id="sidenote-monads-and-applicatives"><span class="header-section-number">15.8</span> Sidenote: Monads and Applicatives</h2>
<p>So what’s the relationship between an Monad and an Applicative? If an Applicative is also a Monad, the following laws hold:</p>
<div class="sourceCode" id="cb387"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb387-1" data-line-number="1">pure <span class="fu">===</span> return</a>
<a class="sourceLine" id="cb387-2" data-line-number="2"></a>
<a class="sourceLine" id="cb387-3" data-line-number="3">fmap <span class="fu">===</span> liftM</a>
<a class="sourceLine" id="cb387-4" data-line-number="4"></a>
<a class="sourceLine" id="cb387-5" data-line-number="5">fmap f op <span class="fu">===</span> <span class="kw">do</span> x <span class="ot">&lt;-</span> op</a>
<a class="sourceLine" id="cb387-6" data-line-number="6"> return (f x)</a>
<a class="sourceLine" id="cb387-7" data-line-number="7"></a>
<a class="sourceLine" id="cb387-8" data-line-number="8">liftA2 <span class="fu">===</span> liftM2</a>
<a class="sourceLine" id="cb387-9" data-line-number="9"></a>
<a class="sourceLine" id="cb387-10" data-line-number="10">liftA2 f op1 op2 <span class="fu">===</span> <span class="kw">do</span> x <span class="ot">&lt;-</span> op1</a>
<a class="sourceLine" id="cb387-11" data-line-number="11"> y <span class="ot">&lt;-</span> op2</a>
<a class="sourceLine" id="cb387-12" data-line-number="12"> return (f x y)</a>
<a class="sourceLine" id="cb387-13" data-line-number="13"></a>
<a class="sourceLine" id="cb387-14" data-line-number="14">op1 <span class="fu">*&gt;</span> op2 <span class="fu">===</span> op1 <span class="fu">&gt;&gt;</span> op2</a>
<a class="sourceLine" id="cb387-15" data-line-number="15"></a>
<a class="sourceLine" id="cb387-16" data-line-number="16">op1 <span class="fu">&lt;*&gt;</span> op2 <span class="fu">===</span> <span class="kw">do</span> f <span class="ot">&lt;-</span> op1</a>
<a class="sourceLine" id="cb387-17" data-line-number="17"> x <span class="ot">&lt;-</span> op2</a>
<a class="sourceLine" id="cb387-18" data-line-number="18"> return (f x)</a></code></pre></div>
<p>When working in a <code>Monad</code>, you can freely mix <code>Applicative</code> and <code>Functor</code> with <code>Monad</code> operations. As an example, let’s rewrite <code>mapM</code> until it only uses applicative operations, and thus get an implementation for <code>traverse</code>. This is our starting point:</p>
<div class="sourceCode" id="cb388"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb388-1" data-line-number="1">myMapM op [] <span class="fu">=</span> return []</a>
<a class="sourceLine" id="cb388-2" data-line-number="2">myMapM op (x<span class="fu">:</span>xs) <span class="fu">=</span> <span class="kw">do</span> y <span class="ot">&lt;-</span> op x</a>
<a class="sourceLine" id="cb388-3" data-line-number="3"> ys <span class="ot">&lt;-</span> myMapM op xs</a>
<a class="sourceLine" id="cb388-4" data-line-number="4"> return (y<span class="fu">:</span>ys)</a></code></pre></div>
<p>GHCi tells us it only works for Monads:</p>
<div class="sourceCode" id="cb389"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb389-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">&gt;</span> <span class="fu">:</span>t myMapM</a>
<a class="sourceLine" id="cb389-2" data-line-number="2"><span class="ot">myMapM ::</span> <span class="dt">Monad</span> m <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> m b) <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> m [b]</a></code></pre></div>
<p>Let’s apply the <code>pure === return</code> and the <code>liftA2</code> laws from above:</p>
<div class="sourceCode" id="cb390"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb390-1" data-line-number="1">myMapM op [] <span class="fu">=</span> pure []</a>
<a class="sourceLine" id="cb390-2" data-line-number="2">myMapM op (x<span class="fu">:</span>xs) <span class="fu">=</span> liftA2 (<span class="fu">:</span>) (op x) (myMapM op xs)</a></code></pre></div>
<p>Ta-da! Now <code>myMapM</code> works for any <code>Applicative</code>:</p>
<div class="sourceCode" id="cb391"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb391-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">&gt;</span> <span class="fu">:</span>t myMapM</a>
<a class="sourceLine" id="cb391-2" data-line-number="2"><span class="ot">myMapM ::</span> <span class="dt">Applicative</span> f <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> f b) <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> f [b]</a></code></pre></div>
<h2 id="quiz-5"><span class="header-section-number">15.9</span> Quiz</h2>
<p>What’s the type of <code>x</code> in <code>liftA2 not Nothing x</code>?</p>
<ol class="quiz">
<li>
<code>Applicative f =&gt; f Bool</code>
</li>
<li>
<code>Applicative Bool</code>
</li>
<li class="correct">
<code>Maybe Bool</code>
</li>
</ol>
<p>How many elements does <code>liftA2 f xs ys</code> have when <code>xs</code> and <code>ys</code> are lists?</p>
<ol class="quiz">
<li>
<code>length xs + length ys</code>
</li>
<li class="correct">
<code>length xs * length ys</code>
</li>
<li>
<code>min (length xs) (length ys)</code>
</li>
</ol>
<p>Which of these expressions is equivalent to <code>liftA2 f x y</code>? There might be multiple correct answers.</p>
<ol class="quiz">
<li class="correct">
<code>f &lt;$&gt; x &lt;*&gt; y</code>
</li>
<li>
<code>f &lt;*&gt; x &lt;*&gt; y</code>
</li>
<li>
<code>f &lt;*&gt; x &lt;$&gt; y</code>
</li>
<li class="correct">
<code>fmap f x &lt;*&gt; y</code>
</li>
<li class="correct">
<code>pure f &lt;*&gt; x &lt;*&gt; y</code>
</li>
</ol>
<p>If <code>f :: X -&gt; Maybe Y</code> and <code>xs :: [X]</code>, which of these expressions has a type different from the others?</p>
<ol class="quiz">
<li>
<code>fmap f xs</code>
</li>
<li class="correct">
<code>traverse f xs</code>
</li>
<li>
<code>map f xs</code>
</li>
</ol>
<p>For which <code>Applicative</code> do the expressions <code>pure x &lt;* pure y</code> and <code>pure x &lt;|&gt; pure y</code> have the different result?</p>
<ol class="quiz">
<li>
<code>Maybe</code>
</li>
<li>
<code>[]</code>
</li>
<li class="correct">
<code>Validation</code>
</li>
</ol>
<h2 id="exercises-6"><span class="header-section-number">15.10</span> Exercises</h2>
<ul>
<li><a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set15.hs">Set15</a></li>
<li><a href="https://forms.gle/soVtMeGBxSo6u5zp6">Remember to give feedback!</a></li>
</ul>
</div>
</div>
</body>