12/08/2020 Code (Week 7 Video)
Code (Week 7 Video)
Applicative Functors
Two applicative versions for Lists
pureZ :: a -> [a]
pureZ a = a:pureZ a
applyListsZ :: [a -> b] -> [a] -> [b]
applyListsZ (f:fs) (x:xs) = f x : applyListsZ fs xs
applyListsZ [] _ = []
applyListsZ _ [] = []
pureC :: a -> [a]
pureC a = [a]
applyListsC :: [a -> b] -> [a] -> [b]
applyListsC (f:fs) args = map f args ++ applyListsC fs args
applyListsC [] args = []
Maybe as an Applicative
type Name = String
type ZID = Int
data Program = COMP | SENG | BINF | CENG deriving (Show, Eq)
type StudentRecord = (Name, ZID, Program)
lookupID :: Name -> Maybe ZID
lookupID “Liam” = Just 3253158
lookupID “Unlucky” = Just 4444444
lookupID “Prosperous” = Just 8888888
lookupID _ = Nothing
lookupProgram :: Name -> Maybe Program
lookupProgram “Liam” = Just COMP
lookupProgram “Unlucky” = Just SENG
lookupProgram “Prosperous” = Just CENG
lookupProgram _ = Nothing
makeRecord :: ZID -> Program -> Name -> StudentRecord
www.cse.unsw.edu.au/~cs3141/20T2/Week 07/1Vid/Code.html
1/5
12/08/2020 Code (Week 7 Video)
Functor Laws for Applicative
These are proofs not Haskell code:
fmap f x = pure f <*> x
— The two functor laws are:
1. fmap id x == x
2. fmap f (fmap g x) == fmap (f.g) x
— Proof:
1) pure id <*> x == x — true by Identity law
2) pure f <*> (pure g <*> x)
== pure (.) <*> pure f <*> pure g <*> x –Composition< == pure ((.) f) <*> pure g <*> x –Homomorphism == pure (f.g) <*> x –Homomorphism
Functions as Applicative
The Applicative instance for functions lets us pass the same argument into multiple functions without repeating ourselves.
makeRecord zid pr name = (name,zid,pr)
liam :: Maybe StudentRecord
liam = let mzid = lookupID “Liam”
mprg = lookupProgram “Liam”
in pure makeRecord <*> mzid <*> mprg <*> pure “Liam”
— pure :: a -> Maybe a
— fmap :: (a -> b) -> Maybe a -> Maybe b
instance Applicative ((->) x) where
pure :: a -> x -> a
pure a x = a
(<*>) :: (x -> (a -> b)) -> (x -> a) -> (x -> b)
(<*>) xab xa x = xab x (xa x)
www.cse.unsw.edu.au/~cs3141/20T2/Week 07/1Vid/Code.html
2/5
12/08/2020 Code (Week 7 Video)
Tuples as Applicative
The tuple instance for Applicative lets us combine secondary outputs from functions into one secondary output without manually combining them.
instance Functor ((,) x) where
fmap :: (a -> b) -> (x,a) -> (x,b)
fmap f (x,a) = (x,f a)
instance Monoid x => Applicative ((,) x) where
pure :: a -> (x,a)
pure a = (mempty ,a)
(<*>) :: (x,a -> b) -> (x, a) -> (x, b)
(<*>) (x, f) (x’,a) = (x <> x’, f a)
It requires Monoid here to combine the values, and to provide a default value for pure .
f :: A -> (Log, B)
g :: X -> (Log, Y)
a :: A
x :: X
combine :: B -> Y -> Z
test :: (Log, Z)
test = combine <$> f a <*> g x — instead of
— — —
let (l1, b) = f a
(l2, y) = g x
in (l1 <> l2, combine b y)
Monads Maybe Monad
— f (g x) (h x) (i x)
—
— Can be written as:
— (pure f <*> g <*> h <*> i) x
www.cse.unsw.edu.au/~cs3141/20T2/Week 07/1Vid/Code.html
3/5
12/08/2020 Code (Week 7 Video)
An example:
db :: [(ZID, Name)]
db = [(3253158, “Liam”),
(8888888, “Rich”),
(4444444, “Mort”)]
studentNames :: [ZID] -> Maybe [Name]
studentNames [] = pure []
studentNames (z:zs) = do
n <- lookup z db
ns <- studentNames zs
pure (n:ns)
-- briefer but less clear with applicative notation:
-- studentNames (z:zs) = (:) <$> lookup z db <*> studentNames zs
The Either Monad
studentNames :: [ZID] -> Either ZID [Name]
studentNames [] = pure []
studentNames (z:zs) = do
n <- case lookup z db of
Just v -> Right v
Nothing -> Left z
ns <- studentNames zs
pure (n:ns)
List Monad
An example
(>>=) :: [a] -> (a -> [b]) -> [b]
(>>=) as f = concatMap f as
(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
(>>=) Nothing f = Nothing
(>>=) (Just a) f = f a
roll :: [Int]
roll = [1,2,3,4,5,6]
www.cse.unsw.edu.au/~cs3141/20T2/Week 07/1Vid/Code.html
4/5
12/08/2020 Code (Week 7 Video)
The Gen Monad
data Tree a = Leaf
| Branch a (Tree a) (Tree a)
deriving (Show, Eq)
instance Arbitrary (Tree Int) where
arbitrary = do
mn <- (arbitrary :: Gen Int)
Positive delta <- arbitrary
let mx = mn + delta
searchTree mn mx
where
searchTree :: Int -> Int -> Gen (Tree Int)
searchTree mn mx
| mn >= mx = pure Leaf
| otherwise = do
v <- choose (mn,mx)
l <- searchTree mn v
r <- searchTree (v+1) mx
pure (Branch v l r)
diceGame = do
d1 <- roll
d2 <- roll
if (abs (d1 - d2) < 2) then do
d2' <- roll
pure (abs (d1 - d2'))
else
pure (abs (d1 - d2))
www.cse.unsw.edu.au/~cs3141/20T2/Week 07/1Vid/Code.html
5/5