Agenda
Some Haskell Types
List
data [] a = [] | a : [a]Maybe
data Maybe a = Nothing | Just aMaybe
data Maybe a = Nothing | Just ahead' :: [a] -> Maybe a
head' [] = Nothing
head' (x:_) = Just xghci> head' []
Nothing
ghci> head' [1,2,3]
Just 1Either
data Either a b = Left a | Right bEither
data Either a b = Left a | Right bhead' :: [a] -> Either String a
head' [] = Left "Empty list"
head' (x:_) = Right xghci> head' []
Left "Empty list"
ghci> head' [1,2,3]
Right 1Tree Type
data Tree a = Empty
| Node a (Tree a) (Tree a)Typeclasses
Typeclasses
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
x == y = not (x /= y)
x /= y = not (x == y) Tree as Eq Typeclass
instance (Eq a) => Eq (Tree a) where
Empty == Empty = True
(Node x tx1 tx2) == (Node y ty1 ty2)
| x == y = tx1 == ty1 && tx2 == ty2
| otherwise = False
_ == _ = FalseTypeclasses
data Tree a = Empty
| Node a (Tree a) (Tree a)
deriving(Eq)Functors
What are functors?
Functor Typeclass
class Functor f where
fmap :: (a -> b) -> f a -> f bLists are Functors
multiply2 :: [Int] -> [Int]
multiply2 xs = map (*2) xs
ghci> multiply2 [1,2,3]
[2,4,6]List Functor Instance
instance Functor [] where
fmap f xs = map f xsmap' :: (a -> b) -> [a] -> [b]
map' _ [] = []
map' f (x:xs) = (f x):map' f xsMaybe as Functor
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just x) = Just (f x)Maybe as Functor
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just x) = Just (f x)ghci> fmap (*2) (Just 4)
Just 8
ghci> fmap (*2) Nothing
NothingEither as Functor
instance Functor (Either a) where
fmap _ (Left x) = Left x
fmap f (Right x) = Right (f x)Either as Functor
instance Functor (Either a) where
fmap _ (Left x) = Left x
fmap f (Right x) = Right (f x)ghci> fmap (*2) (Left 4)
Left 4
ghci> fmap (*2) (Right 4)
Right 8Functor Laws
1. Mapping the id function over a functor should return the same functor
Functor Laws
1. Mapping the id function over a functor should return the same functor
id :: a -> a
id x = xFunctor Laws
1. Mapping the id function over a functor should return the same functor
id :: a -> a
id x = xghci> map id [1,2,3]
[1,2,3]Functor Laws
2. Composing two functions and mapping the result should be the same as first mapping one function and then the other
Functor Laws
2. Composing two functions and mapping the result should be the same as first mapping one function and then the other
(.) :: (b -> c) -> (a -> b) -> (a -> c)
f . g = (\x -> f (g x))fmap (f . g) = fmap f . fmap g
Functor Laws
2. Composing two functions and mapping the result should be the same as first mapping one function and then the other
(.) :: (b -> c) -> (a -> b) -> (a -> c)
f . g = (\x -> f (g x))composed = (+1) . (*2)
ghci> map composed [1,2,3]
[3, 5, 7]Functor Laws
2. Composing two functions and mapping the result should be the same as first mapping one function and then the other
(.) :: (b -> c) -> (a -> b) -> (a -> c)
f . g = (\x -> f (g x))composed = (+1) . (*2)
ghci> map composed [1,2,3]
[3, 5, 7]ghci> map (+1) $ map (*2) [1,2,3]
[3,5,7]Tree as a Functor
instance Functor Tree where
fmap _ Empty = Empty
fmap f (Node x tL tR) = Node (f x) (fmap f tL) (fmap f tR)data Tree a = Empty
| Node a (Tree a) (Tree a)Tree as a Functor
ghci> fmap (*2) Empty
Empty
ghci> fmap (*2) (Node 4 (Node 3 Empty Empty) Empty)
(Node 8 (Node 6 Empty Empty) Empty)instance Functor Tree where
fmap _ Empty = Empty
fmap f (Node x tL tR) = Node (f x) (fmap f tL) (fmap f tR)data Tree a = Empty
| Node a (Tree a) (Tree a)Tree as a Functor
ghci> fmap id Empty
Empty
ghci> fmap id (Node 4 (Node 3 Empty Empty) Empty)
(Node 4 (Node 3 Empty Empty) Empty)instance Functor Tree where
fmap _ Empty = Empty
fmap f (Node x tL tR) = Node (f x) (fmap f tL) (fmap f tR)data Tree a = Empty
| Node a (Tree a) (Tree a)Tree as a Functor
ghci> fmap (+1) $ fmap (*2) (Node 4 (Node 3 Empty Empty) Empty)
(Node 9 (Node 7 Empty Empty) Empty)
ghci> fmap ((+1) . (*2)) (Node 4 (Node 3 Empty Empty) Empty)
(Node 9 (Node 7 Empty Empty) Empty)
instance Functor Tree where
fmap _ Empty = Empty
fmap f (Node x tL tR) = Node (f x) (fmap f tL) (fmap f tR)data Tree a = Empty
| Node a (Tree a) (Tree a)Mapping multi-parameter functions
ghci> :t fmap (*) (Just 4)
fmap (*) (Just 4) :: Num a => Maybe (a -> a)
Applicative Functors
Applicative Functors
class (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f bList as Applicative Functor
instance Applicative [] where
pure x = [x]
fs <*> xs = [f x | f <- fs, x <- xs]class (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f bList as Applicative Functor
instance Applicative [] where
pure x = [x]
fs <*> xs = [f x | f <- fs, x <- xs]ghci> [(*0),(+100),(^2)] <*> [1,2,3]
[0,0,0,101,102,103,1,4,9] ghci> [(+),(*)] <*> [1,2] <*> [3,4]
[4,5,5,6,3,4,6,8]Maybe as Applicative Functor
class (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f binstance Applicative Maybe where
pure x = Just x
(Just f) <*> a = fmap f a
Nothing <*> _ = NothingMaybe as Applicative Functor
instance Applicative Maybe where
pure x = Just x
(Just f) <*> a = fmap f a
Nothing <*> _ = Nothingghci> pure (*) <*> (Just 2) <*> Just 4
Just 8ghci> pure (*) <*> (Just 2) <*> Just 4
Just 8ghci> fmap (*) (Just 2) <*> Just 4
Just 8(<$>) :: (Functor f) => (a -> b) -> f a -> f b
f <$> x = fmap f xMaybe as Applicative Functor
ghci> pure (*) <*> (Just 2) <*> Just 4
Just 8ghci> fmap (*) (Just 2) <*> Just 4
Just 8(<$>) :: (Functor f) => (a -> b) -> f a -> f b
f <$> x = fmap f xghci> (*) <$> (Just 2) <*> Just 4
Just 8Maybe as Applicative Functor
Maybe as Applicative Functor
ghci> (*) <$> Nothing <*> Just 4
Nothingghci> (*) <$> Just 2 <*> Nothing
NothingDifference to Monads
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m bclass (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f bDifference to Monads
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m baddOne :: Int -> Maybe Int
addOne x
| x <= 4 = Just (x + 1)
| otherwise = Nothingghci> Just 3 >>= addOne
Just 4ghci> Just 3 >>= addOne >>= addOne
Just 5ghci> Just 3 >>= addOne >>= addOne >>= addOne >>= addOne
NothingEither' as Applicative Functor
instance (Monoid a) => Applicative Either' a where
pure x = Right' x
Right' f <*> Right' x = Right' (f x)
Right' _ <*> Left' e = Left' e
Left' e <*> Right' _ = Left' e
Left' e1 <*> Left' e2 = Left' (e1 `mappend` e2)class (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f bEither' as Applicative Functor
instance (Monoid a) => Applicative Either' a where
pure x = Right' x
Right' f <*> Right' x = Right' (f x)
Right' _ <*> Left' e = Left' e
Left' e <*> Right' _ = Left' e
Left' e1 <*> Left' e2 = Left' (e1 `mappend` e2)class (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f bghci> Right' (+) <*> Left' ["err1"] <*> Left' ["err2"]
Left' ["err1", "err2"]