Introduction to Functors

Agenda
- Some Types
- Typeclasses
- Functors
- Applicative Functors

Some Haskell Types

List

data [] a = [] | a : [a]
Maybe

data Maybe a = Nothing | Just a
Maybe

data Maybe a = Nothing | Just a
head' :: [a] -> Maybe a
head' [] = Nothing
head' (x:_) = Just x
ghci> head' []
Nothing
ghci> head' [1,2,3]
Just 1
Either

data Either a b = Left a | Right b
Either

data Either a b = Left a | Right b
head' :: [a] -> Either String a
head' [] = Left "Empty list"
head' (x:_) = Right x
ghci> head' []
Left "Empty list"
ghci> head' [1,2,3]
Right 1
Tree 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
_ == _ = False
Typeclasses

- 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 b
Lists 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 xs
map' :: (a -> b) -> [a] -> [b]
map' _ [] = []
map' f (x:xs) = (f x):map' f xs
Maybe 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
Nothing
Either 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 8
Functor 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 = x
Functor Laws

1. Mapping the id function over a functor should return the same functor
id :: a -> a
id x = x
ghci> 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 b
List 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 b
List 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 b
instance Applicative Maybe where
pure x = Just x
(Just f) <*> a = fmap f a
Nothing <*> _ = Nothing
Maybe as Applicative Functor

instance Applicative Maybe where
pure x = Just x
(Just f) <*> a = fmap f a
Nothing <*> _ = Nothing
ghci> pure (*) <*> (Just 2) <*> Just 4
Just 8

ghci> pure (*) <*> (Just 2) <*> Just 4
Just 8
ghci> fmap (*) (Just 2) <*> Just 4
Just 8
(<$>) :: (Functor f) => (a -> b) -> f a -> f b
f <$> x = fmap f x
Maybe as Applicative Functor

ghci> pure (*) <*> (Just 2) <*> Just 4
Just 8
ghci> fmap (*) (Just 2) <*> Just 4
Just 8
(<$>) :: (Functor f) => (a -> b) -> f a -> f b
f <$> x = fmap f x
ghci> (*) <$> (Just 2) <*> Just 4
Just 8
Maybe as Applicative Functor

Maybe as Applicative Functor
ghci> (*) <$> Nothing <*> Just 4
Nothing
ghci> (*) <$> Just 2 <*> Nothing
Nothing
Difference to Monads

class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
class (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
Difference to Monads

class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
addOne :: Int -> Maybe Int
addOne x
| x <= 4 = Just (x + 1)
| otherwise = Nothing
ghci> Just 3 >>= addOne
Just 4
ghci> Just 3 >>= addOne >>= addOne
Just 5
ghci> Just 3 >>= addOne >>= addOne >>= addOne >>= addOne
Nothing
Either' 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 b
Either' 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 b
ghci> Right' (+) <*> Left' ["err1"] <*> Left' ["err2"]
Left' ["err1", "err2"]
deck
By pat310
deck
- 1,287