Introduction to Functors

Agenda
- Some Types
- Typeclasses
- Functors
- Applicative Functors

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

- Eq
- Ord
- Enum
- Show
- Read
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 8
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 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"]deck
By pat310
deck
- 1,402