g()
return?
f(3)
return?
f
has the same type as in the previous example.
g()
return?
f
has the same type as in the previous examples.
newPage
changes the state
(has both extra input and extra output).
startNewPage
changes the state and performs IO operations.
f
has the same type as in the previous examples.
All inputs and outputs have to be visible in the type:
Pure function: | Input -> Output |
Extra input: | Input -> Extra -> Output |
Extra output: | Input -> (Extra,Output) |
Changing the state: | Input -> State -> (State,Output) |
IO operations: | Input -> IO Output |
Sometimes no result: | Input -> Maybe Output |
Many results: | Input -> [Output] |
h
that combines two functions
f
and g
that both have additional effects.
-- Pure functions: Input -> Output h x = g (f x) -- Extra input: Input -> Extra -> Output h x e = g (f x e) e
-- Extra output: Input -> (Extra,Output) h x = (o1<>o2,y2) where (o1,y1) = f x (o2,y2) = g y1 -- Changing the state: Input -> State -> (State,Output) h x s0 = (s2,y2) where (s1,y1) = f x s0 (s2,y2) = g y1 s1
-- IO operations: Input -> IO Output h x = do y1 <- f x y2 <- g y1 return y2 -- Sometimes no result: Input -> Maybe Output h x = case f x of Nothing -> Nothing Just y -> g y -- Many results: h x = [y2 | y1 <- f x, y2 <- g y1]
h x = g (f x)
h x = (o1<>o2,y2) where (o1,y1) = f x (o2,y2) = g y1
=<<
h x = g =<< f x
h x = g (f x)
h x = (o1<>o2,y2) where (o1,y1) = f x (o2,y2) = g y1
=<<
h x = g =<< f x
g =<< fx = (o1<>o2,y2) where (o1,y1) = fx (o2,y2) = g y1
=<<
=<<
Taking another look at the types:
Type of effect | Function type |
---|---|
Pure function: | Input -> Output |
Extra input: | Input -> Extra -> Output |
Extra output: | Input -> (Extra,Output) |
Changing the state: | Input -> State -> (State,Output) |
IO operations: | Input -> IO Output |
Sometimes no result: | Input -> Maybe Output |
Many results: | Input -> [Output] |
We can factor them like this:
Type of effect | The common pattern | The difference |
---|---|---|
Pure function: | Input -> M Output | M a a |
Extra input: | Input -> M Output | M a Extra -> a |
Extra output: | Input -> M Output | M a (Extra,a) |
Changing the state: | Input -> M Output | M a State->(State,a) |
IO operations: | Input -> M Output | M a IO a |
Sometimes no result: | Input -> M Output | M a Maybe a |
Many results: | Input -> M Output | M a [a] |
Input -> M Output
M
M
(=<<) :: (a -> M b) -> M a -> M b
($) :: (a -> b) -> a -> b
=<<
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a->m b) -> m b
-- ...
(=<<) :: Monad m => (a->m b) -> m a -> m b
f=<<x = x>>=f
m
do
>>=
do x <- m1; y <- m2 x; return (x+y)
m1 >>= (\x -> do y <- m2 x; return (x+y))
m1 >>= (\x -> m2 x >>= (\y -> return (x+y)))
=<<
do
Operator | Function | Argument | Result |
---|---|---|---|
$ | a->b | a | b |
<$> | a->b | m a | m b |
<*> | m (a->b) | m a | m b |
=<< | a->m b | m a | m b |
<$>
<*>
f <$> x = fmap f x f =<< m = m >>= f
class Functor f where fmap :: (a->b) -> f a -> f b f <$> x = fmap f x
map
map :: (a->b) -> [a] -> [b] fmap :: Functor f => (a->b) -> f a -> f b
<$>
rNumeric :: Gen Rank rNumeric = do n <- choose (2,10) return (Numeric n)
rNumeric = Numeric <$> choose (2,10)
number :: Parser Integer number = do ds <- oneOrMore digit return (read ds)
number = read <$> oneOrMore digit
class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a->b) -> f a -> f b
Applicative
Monad
<*>
=<<
pure
return
<*>
rCard :: Gen Card rCard = do s <- rSuit r <- rRank return (Card s r)
rCard = Card <$> rSuit <*> rRank
oneOrMore :: Parser item -> Parser [item] oneOrMore item = do i <- item is <- zeroOrMore item return (i:is)
oneOrMore item = (:) <$> item <*> zeroOrMore item
Either
Maybe
Nothing
evalM