Agenda
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
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"]