Files
notes/docs/lectures/compilers/06_applicative_functors.md
T

96 lines
2.1 KiB
Markdown

# Applicative Functors
Types: `Bool`, `Int`, `Char`, `[Char] = String`
Type Constructors: `Maybe`, `[]`
(type) classes: `Eq`, `Show`, `Functor`
```haskell
newtype Parser a = P ( String -> [a, String])
parse :: Parser a -> String -> [(a, String)]
parse (P p) s = p s -- s's can be cancelled from both sides
instance Functor Parser where
-- fmap :: (a -> b) -> Parser a -> Parser b
fmap g pa = P (\s -> [(g x, s1) |
(x,s1) <- parse pa s])
```
Applicative - motivation
```haskell
Functor f
fmap0 :: a -> f a
fmap1 :: (a -> b) -> f a -> f b
-- cannot do this with functors ie cannot deal with multiple parameters
fmap2 :: (a -> b -> c) -> f a -> f b -> f c
fmap3 :: (a -> ... n) -> f a -> ... f n
```
`Functor f` can do `fmap1` however cannot do `fmap0` or `fmap2` etc.
**Remember**: `a -> b -> c == a -> (b -> c)`
For `fmap2` we can use `fmap2 :: (a -> (b -> c)) -> f a -> f (a -> b)`
would need: `f(b -> c) -> f b -> f c`
```haskell
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
-- <*> infix operator
-- NOTE its f (a -> b) and not (a -> b) in fmap1
-- fmap1 not part of the applicative class
```
Writing `fmap3` in an applicative functor
```haskell
fmap3 :: g x y z = (pure g) <*> x <*> y <*> z
```
##### Example Maybe
```haskell
instance Applicative Maybe where
-- pure :: a -> Maybe a
pure x = Just x
-- (<*>) :: Maybe (a -> b) -> Maybe a -> Maybe b
Just g <*> (Just x) = Just (g x)
_ <*> _ = Nothing
```
##### Example Lists
```haskell
instance Applicative [] where
-- pure :: a -> [a]
pure x = [x]
-- (<*>) :: [a -> b] -> [a] -> [b]
gs <*> xs = [g x | g <- gs, x <- xs]
```
##### Example Parser
```haskell
instance Applicative Parser where
-- pure :: a -> Parser a
-- newtype Parser a = P ( String -> [(a, String)] )
pure x = P (\s -> [(x,s)])
-- <*> :: Parser (a -> b) -> Parser a -> Parser b
pf <*> pa = P (\s -> [ (f x, s2) |
(f, s1) <- parse pf s,
(x, s2) <- parse pa s1)])
```
All parse does is apply a parser
`parse :: Parser a -> String -> [(a, String)]`
Where `P` is the constructor
`parse ( P p ) = p`