Functors, Applicatives, Monads¶
Functors¶
inc :: [Int] -> [Int]
inc [] = []
inc (n:ns) = n+1 : inc ns
sqr :: [Int] -> [Int]
sqr [] = []
sqr (n:ns) = n^2 : sqr ns
Functors abstract the idea of mapping a function over each element of a data structure. Rather than writing dedicated mapping functions for every parameterised type (such as map for lists), Haskell captures this pattern with the Functor type class.
map :: (a -> b) -> [a] -> [b]
map g [] = []
map g (x:xs) = g x : map g xs
The class declaration:
class Functor f where
fmap :: (a -> b) -> f a -> f b
Type Parameter
f: Must be a parameterised type (a type constructor taking one argument, such as[],Maybe, orIO).fmap: Applies a pure function(a -> b)to the element(s) insidef ato return a new structuref b.
Standard and Custom Functor Examples¶
Lists¶
instance Functor [] where
-- fmap :: (a -> b) -> [a] -> [b]
fmap = map
fmap (+1) [1,2,3]
[2,3,4]
map (`replicate` "*") [1,2,3]
[["*"],["*","*"],["*","*","*"]]
Maybe¶
instance Functor Maybe where
-- fmap :: (a -> b) -> Maybe a -> Maybe b
fmap g Nothing = Nothing
fmap g (Just x) = Just (g x)
fmap (+1) Nothing
Nothing
fmap (*2) (Just 3)
Just 6
fmap not (Just False)
Just True
Binary Tree (Leaf Data)¶
data Tree a = Leaf a | Node (Tree a) (Tree a) deriving Show
instance Functor Tree where
-- fmap :: (a -> b) -> Tree a -> Tree b
fmap g (Leaf x) = Leaf (g x)
fmap g (Node l r) = Node (fmap g l) (fmap g r)
fmap length (Leaf "abc")
Leaf 3
fmap even (Node (Leaf 1) (Leaf 2))
Node (Leaf False) (Leaf True)
Input Output (IO)¶
The above 3 examples can be viewed as "container" functors! The next one is different. IO functor represents input/output actions!
instance Functor IO where
-- fmap :: (a -> b) -> IO a -> IO b
fmap g mx = do { x <- mx; return (g x) }
fmap show (return True)
"True"
Generic functions over Functors¶
inc :: Functor f => f Int -> f Int
inc = fmap (+1)
inc (Just 1)
Just 2
inc [1, 2, 3, 4, 5]
[2,3,4,5,6]
inc (Node (Leaf 1) (Leaf 2))
Node (Leaf 2) (Leaf 3)
Equational Functor Laws¶
Every valid instance of Functor must obey two fundamental laws:
Identity Preservation: $$\text{fmap id} = \text{id}$$
Composition Preservation: $$\text{fmap } (g \cdot h) = \text{fmap } g \cdot \text{fmap } h$$
What if a functor does not satisfy the functor laws?¶
instance Functor [] where
-- fmap :: (a -> b) -> f a -> f b
fmap _ [] = []
fmap g (x:xs) = fmap g xs ++ [g x] -- we are reversing the items in the list!
<interactive>:1:10: error: [GHC-59692]
Duplicate instance declarations:
instance Functor [] -- Defined at <interactive>:1:10
instance Functor [] -- Defined in ‘GHC.Base’
fmap id [1,2] = [2,1] id [1,2] = [1,2]
fmap (not . even) [1,2] = [False, True] (fmap not . fmap even) [1,2] = fmap not (fmap even [1,2]) = fmap not [False,True] = [True, False]