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,224