95 lines
2.1 KiB
Markdown
95 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, it 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`
|