Jan van Eijck
Sept 27, 2016
> module FSA4 where
>
> import Data.Char
> import Control.Monad.State
> import Control.Applicative
> import System.Random
IO (Input/Output) is interaction with the outside world. IO in Haskell is different from IO in imperative or object-oriented languages, because the functional paradigm isolates the purely functional kernel of the language from the outside world. This lecture explains, among other things, why Hello World
is not the simplest possible program to write in Haskell.
Monads as Containers
Hello World
in Haskell is the following program:
*FSA4> putStrLn "Hello World"
Hello World
This outputs a string to the screen. A more elaborate version would first ask for user input, which means that interaction with the outside world takes place. Such interaction is called a side effect. Pure functions do not have side effects; they just compute values, and for this they do not use information from the outside world. This purity is a very good thing, for it allows us to reason about functional computation in a mathematical way.
Input-Output involves interaction with the outside world, hence side effects. The Haskell method of dealing with side effects, and isolating them from the pure functional kernel of the language is by putting them in a wrapper. Such wrappers are called monads.
The concept and its name are borrowed from category theory, but monadic programming can be understood without tracing this connection.
In the same way, IO in Haskell can be understood without understanding monads. But understanding the IO monad will improve your capabilities of handling IO in Haskell, and understanding monads will improve your Haskell coding skills in general.
One useful analogy is to view monads as wrappers or containers. Let's start with this analogy. Monads are container types used to model various kinds of computations.
You are already familiar with some examples.
Lists are containers, so lists are monads.
The type Maybe a
is a container, so the type Maybe a
is a monad.
Exception Types
An exception type is a type of the form Maybe a
. Exceptions types can be used to hide failure checks. An example of a function that returns an exception type is lookup
:
lookup :: Eq a => a -> [(a,b)] -> Maybe b
lookup k ((k',v):_) | k == k' = Just v
lookup k (_:xs) = lookup k xs
lookup k [] = Nothing
The Maybe Monad
The Maybe
datatype is predefined like this:
data Maybe a = Nothing | Just a
deriving (Eq, Ord)
This is declared as both a functor and a monad. The functor declaration looks as follows:
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)
Just like Eq
, Ord
, Show
and Monad
, Functor
is a type class, which means that certain functions are predefined for it.
An important difference however is that Monad
is a type class which does not apply to concrete types but to type constructors. For example, instance Eq String ...
will make the equality test (==) available on Strings.
In contrast,
instance Functor Maybe ...
does not give us functions working on things of type Maybe
because nothing is of type Maybe
.
Things can be of Type Maybe Int
, Maybe String
, etc. and what the Functor and Monad instances do is to give us functions working on all of these.
For more info on this, see this section on "Kinds and some type-foo" in LYHFGG and try out :k
in GHCi.
Functors
A functor is a kind of container, where it is possible to apply a single function to each object in the container. So a functor is a thing that can be mapped over, and the predefined function for that is fmap
. The function fmap
takes an ordinary function of type a -> b
as input, and produces a function of type f a -> f b
.
Since Maybe
is a functor, we have, e.g., the following:
*FSA4> :t fmap succ (Just 3)
fmap succ (Just 3) :: (Enum b, Num b) => Maybe b
*FSA4> fmap succ (Just 3)
Just 4
Every monad is a functor, so fmap
is defined for every monad, but monads are more specific. They also have three functions (>>=)
, (>>)
and return
defined on them.
The function (>>=)
is called bind
, and the function (>>)
is called then
.
Actually, (>>)
is a simplified version of (>>=)
and can be defined in terms of it.
(>>=)
in turn can be defined in terms of fmap
and a container popping function called join
.
Join
The intuition behind join
is perhaps easier to grasp than that behind (>>=)
, so we start with join
. Here is its type:
join :: Monad m => m (m a) -> m a
Thinking of m
as a container, we see that join
replaces a double container by a single one. The implementation for the case of Maybe
is easy:
join :: Maybe (Maybe a) -> Maybe a
join (Just x) = x
join _ = Nothing
(>>=)
The definition of (>>=)
in terms of join
and fmap
runs as follows:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
k >>= f = join (fmap f k)
This definition expresses that binding k
to f
is the same as first mapping f
over k
, and then joining the result.
(>>)
The function (>>)
can be defined in terms of (>>=)
as follows:
(>>) :: Monad m => m a -> m b -> m b
m >> k = m >>= (\ _ -> k)
The function (>>)
(then
) is a more primitive version of (>>=)
(bind
); it discards the value passed to it by its first argument.
Maybe
is a Monad
, and in this particular case, the three functions are defined as follows:
instance Monad Maybe where
(Just x) >>= k = k x
Nothing >>= _ = Nothing
(Just _) >> k = k
Nothing >> _ = Nothing
return = Just
fail _ = Nothing
To understand these definitions, let us look at the types of bind
, then
and return
. (We forget about fail
for now, for this is included for smooth handling of do notation; see below.)
*FSA4> :t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b
*FSA4> :t (>>)
(>>) :: Monad m => m a -> m b -> m b
*FSA4> :t return
return :: Monad m => a -> m a
The function return
is a wrapping up operator that wraps up arbitrary objects into monads. In the case of Maybe
, all that return
does is wrapping the constructor Just
around its argument, changing the type from a
to Maybe a
.
The function (>>=)
takes an item wrapped in a monad, type m a
, unwraps it to a
, and applies a function of type a -> m b
to the result. In case unwrapping to a
is impossible, this is indicated in the result.
Examples of the use of (>>=)
:
*FSA4> Just 3 >>= \ x -> Just (succ x)
Just 4
*FSA4> Just 3 >>= \ _ -> Nothing
Nothing
*FSA4> Just 3 >>= \ x -> Just [x,x,x]
Just [3,3,3]
*FSA4> Just 3 >>= return
Just 3
*FSA4> Just 3 >>= Just
Just 3
Review Exercise In all these examples, check that you understand the types and the outcomes.
The definition of (>>)
in terms of (>>=)
explains the following:
*FSA4> Just 3 >> Just 4
Just 4
*FSA4> Nothing >> Just 4
Nothing
*FSA4> Nothing >> Nothing
Nothing
Review Exercise Check that you understand the types and the outcomes.
We can also turn things around. The function join
can be defined in terms of (>>=)
. In fact, the following definition is in module Control.Monad.State
:
join :: Monad m => m (m a) -> m a
join xss = xss >>= id
This allows the replacement of a double container by a single container:
*FSA4> join (Just (Just 3))
Just 3
*FSA4> join (Just Nothing)
Nothing
*FSA4> join Nothing
Nothing
Monadic Programming with Exception Types
> table = map (\ x -> (x,x^3)) [1..100]
We want to look up two numbers and add them.
> process :: Int -> Int -> Maybe Int
> process m n = lookup m table >>= \ v ->
> lookup n table >>= \ w -> return (v+w)
*FSA4> lookup 3 table
Just 27
*FSA4> lookup 200 table
Nothing
*FSA4> process 3 5
Just 152
*FSA4> process 0 3
Nothing
*FSA4> process 3 200
Nothing
Lists as Monads
Now let's look at the list container as a monad. List types are functors, and their mapping function fmap
is map
. List types are also monads. Putting a single thing in a list container is done by the function \ x -> [x]
, which can be abbreviated as (:[])
. The return
function for lists is (:[])
.
*FSA4> return 3 :: [Int]
[3]
Binding to return
is the identity on monad types: it maps a thing of type monad b
to itself.
This is in fact the second monad law (see below).
Since lists are monads, binding a list to return
returns the list:
*FSA4> [1,2,3] >>= return
[1,2,3]
Since return
for lists is the function \ x -> [x]
, the following is equivalent:
*FSA4> [1,2,3] >>= \ x -> [x]
[1,2,3]
Let's make a few variations on x -> [x]
and see what we get:
*FSA4> [1,2,3] >>= \ x -> [x,x]
[1,1,2,2,3,3]
*FSA4> [1,2,3] >>= \ x -> [x,x,x]
[1,1,1,2,2,2,3,3,3]
*FSA4> [1,2,3] >>= \ x -> [x,x,x,x]
[1,1,1,1,2,2,2,2,3,3,3,3]
*FSA4> [[1],[2,3],[4]] >>= id
[1,2,3,4]
Note that the final result shows that join
for lists is in fact the concat
function.
Review Exercise Work out what the definition of (>>=)
for list types should look like.
*FSA4> [1,2,3] >>= \ x -> [x,x^2,x^3,x^4]
[1,1,1,1,2,4,8,16,3,9,27,81]
What bind
does is apply an arbitrary wrapping function to everything in a container and collect the results in a single container.
In other words, if f
is of type a -> [b]
and xs
is of type a
, then xs >>= f
is of type [b]
, and the effect of >>=
, in the list case, is given by \ xs f -> concatMap f xs
.
Do Notation
First consider monad objects connected by then
operators. Example:
*FSA4> putStrLn "x" >> putStrLn "y" >> putStrLn 'z'
"x"
"y"
'z'
*FSA4> do putStrLn "x" ; putStrLn "y" ; putStrLn 'z'
"x"
"y"
'z'
Think of the monad objects as a list of actions, and of the do notation of a way of presenting this list like a sequential program.
In a similar way we can translate bind
:
*FSA4> getLine >>= \ x -> putStrLn ("hello "++x)
jan
"hello jan"
*FSA4> do x <- getLine; putStrLn ("hello "++x)
jan
"hello jan"
We can string more than two actions together:
> greetings = do putStrLn ("First name?")
> x <- getLine
> putStrLn ("Second name?")
> y <- getLine
> putStrLn ("hello "++x++" "++y)
Note that the semicolons are superfluous now. This is equivalent to (or syntactic sugar for):
> greetz = putStrLn ("First name?") >>
> getLine >>= \ x ->
> putStrLn ("Second name?") >>
> getLine >>= \ y ->
> putStrLn ("hello "++x++" "++y)
The relation between do-notation and then
or bind
notation is given by:
do { x } = x
do { x ; <statements> }
= x >> do { <statements> }
do { v <- x ; <statements> }
= x >>= \ v -> do { <statements> }
Notice that the final instruction can lead to a pattern match failure. Here is a simple example:
> action = do Just x <- Nothing
> return (x^2)
This looks strange, for the container Nothing
simply does not contain Just x
, so the assumption in the second line that that there is a number x
available that can be squared is just wrong. Still, the interpreter accepts the definition.
The actual translation from do
notation is more involved than the above instruction suggests, and uses a case distinction to catch pattern match failures:
> action' = Nothing >>= f where
> f (Just x) = return x
> f Nothing = fail ""
This is where the definition of fail
in the Maybe monad kicks in.
Trees as Monads
Since a tree is also a kind of container, it makes sense to view trees as monads.
> data Tree a = Leaf a | Branch (Tree a) (Tree a)
> deriving (Eq,Ord,Show)
First, trees can be viewed as functors. Let's put this in a declaration, and define fmap
for trees.
> instance Functor Tree where
> fmap f (Leaf x) = Leaf (f x)
> fmap f (Branch left right) = Branch (fmap f left)
> (fmap f right)
Applicative Functors
Functors with extra structure, in between Functors and Monads ...
See Applicative Functors.
A functor with application provides operations to
embed pure expressions (with pure :: a -> f a
)
sequence computations and combine their results (with (<*>) :: f (a -> b) -> f a -> f b
).
*FSA4> pure (+) <*> Just 2 <*> Just 3
Just 5
*FSA4> pure (.) <*> Just succ <*> Just succ <*> Just 3
Just 5
*FSA4> Just succ <*> (Just succ <*> Just 3)
Just 5
Laws for Applicative Functors
pure id <*> v = v
pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
pure f <*> pure x = pure (f x)
u <*> pure y = pure ($ y) <*> u
The second law is the compostion law. It says that if <*>
is used for composition, then the composition is associative.
In the fourth law, note that ($ y)
is the function that supplies y
as argument to another function.
Relation between fmap
and <*>
:
fmap f x = pure f <*> x
Note that pure
and return
serve the same purpose of lifting, to an applicative function and to a monad, respectively.
Similarly, <*>
and ap
serve the same purpose: application within an applicative functor and within a monad, respectively.
The Functor instance of an Applicative will satisfy:
fmap f x = pure f <*> x
If an Applicative is a Monad, it should also satisfy:
pure = return
(<*>) = ap
See below for ap
(application within a Monad).
*FSA4> [succ, succ.succ] `ap` [1..5]
[2,3,4,5,6,3,4,5,6,7]
*FSA4> Just succ `ap` Just 5
Just 6
Trees can be viewed as applicative functors
> instance Applicative Tree where
> -- pure :: a -> Tree a
> pure = Leaf
> -- (<*>) :: Tree (a -> b) -> Tree a -> Tree b
> (<*>) (Leaf f) atree = fmap f atree
> (<*>) (Branch fl fr) atree = Branch (fl <*> atree) (fr <*> atree)
*FSA4> Branch (Leaf succ) (Leaf (succ.succ)) <*> Leaf 0
Branch (Leaf 1) (Leaf 2)
*FSA4> Branch (Leaf succ) (Leaf (succ.succ)) <*> Branch (Leaf 0) (Leaf 1)
Branch (Branch (Leaf 1) (Leaf 2)) (Branch (Leaf 2) (Leaf 3))
Trees are also instances of Monad
.
Before we give the declaration, let us work out what join
for trees should look like:
join :: Tree (Tree a) -> Tree a
join (Branch left right) = Branch (join left)
(join right)
join (Leaf tree) = tree
Wrapping up an arbitrary thing in a tree is done by means of Leaf
.
Binding a leaf Leaf x
to a function f :: a -> Tree b
is just a matter of applying f
to x
.
Binding a tree Branch left right
to f
is just a matter of recursing over the branches. This gives the following instance declaration of trees as monads:
> instance Monad Tree where
> -- return :: a -> Tree a
> return = Leaf
> -- (>>=) :: Tree a -> (a -> Tree b) -> Tree b
> (Leaf x) >>= f = f x
> (Branch left right) >>= f =
> Branch (left >>= f) (right >>= f)
The IO Monad
Input/output involves interaction with the world. If you want to think of IO a
as a wrapper, then think of it as a container that shields the pure world of Haskell from the outside.
But in the particular case of the IO monad, it is better to think of the monad elements as actions, and to think of IO as interaction.
Here is Hello World
again, with its type:
> hello :: IO ()
> hello = do
> putStrLn "What is your name?"
> n <- getLine
> putStrLn ("Hello " ++ n)
The type of hello
cannot be purely functional, for what hello
does depends on how the interaction with the world, via getLine
, develops.
This is indicated by the type IO ()
.
Getting a random integer involves interaction with the outside world in a similar way, for some aspect of the world (either known or unknown to the programmer) determines what the output will be.
The function getRandomIn
below gives a random integer in a range 0, ..., n
. This uses randomR
which from a generator function g
and a number n
deterministically picks a number in 0, ... , n
and produces a new generator g'
. getStdRandom
gets a generator g
from the system, feeds it to randomR
, gets a pair (m,g')
back, and prints m
while discarding g'
.
> getRandomInt :: Int -> IO Int
> getRandomInt n = getStdRandom (randomR (0,n))
This gives:
*FSA4> getRandomInt 20
16
*FSA4> getRandomInt 20
18
*FSA4> getRandomInt 20
6
*FSA4> getRandomInt 20
11
This can be used in turn to randomly flip the value of an integer:
> randomFlip :: Int -> IO Int
> randomFlip x = do
> b <- getRandomInt 1
> if b==0 then return x else return (-x)
Now we have the ingredients for generating random integer lists. Generating an integer list with integers in the range \(-k, \ldots , k\) and lengths in the range \(0, \ldots , n\):
> getIntL :: Int -> Int -> IO [Int]
> getIntL _ 0 = return []
> getIntL k n = do
> x <- getRandomInt k
> y <- randomFlip x
> xs <- getIntL k (n-1)
> return (y:xs)
Let's translate this back into bind
notation:
> getIntL' :: Int -> Int -> IO [Int]
> getIntL' _ 0 = return []
> getIntL' k n = getRandomInt k >>= \ x ->
> randomFlip x >>= \ y ->
> getIntL k (n-1) >>= \ xs ->
> return (y:xs)
Use this for generating random integer lists by setting the range and length constraints:
> genIntList :: IO [Int]
> genIntList = do
> k <- getRandomInt 20
> n <- getRandomInt 10
> getIntL k n
This gives, e.g.:
*FSA4> genIntList
[0,0,0,0]
*FSA4> genIntList
[-1,-5,-3,-2,-1,6,2,-8]
*FSA4> genIntList
[15,-10,7,-15,5,-13,15,11,13,-11]
*FSA4> genIntList
[0,10,14,0,13,13,-5,-4,15]
*FSA4> genIntList
[2,-1,0,-1,2,2,1,0,1]
The Functor Laws
The Functor Laws state that fmap
should map the source identity element to the target identity element, and that it should map a composition of two functions to the composition of the mapped elements.
fmap id = id
.
fmap (f . g) = (fmap f) . (fmap g)
.
The Monad Laws
The Monad Laws state that return
and bind
should behave like this:
return a >>= k = k a
.
m >>= return = m
.
m >>= \ x -> k x >>= h = (m >>= k) >>= h
.
It is the responsibility of the programmer to ensure that these requirements are met.
The first Monad Law
The first Monad Law says, e.g., that return "hello" >>= putStrLn
and putStrLn "hello"
are equivalent.
Also that Just 5 >>= Just
and Just 5
are equivalent.
The Second Monad Law
The second Monad Law says, e.g., that getLine >>= return
is equivalent to getLine
.
Translating the second Monad Law into do notation, it just says that instead of spuriousGet
we can simply write getLine
.
> spuriousGetline = do x <- getLine
> return x
The Third Monad Law
The third Monad Law expresses the associativity of >>=
. This is perhaps clearer in the version for then
:
m >> (k >> h) = (m >> k) >> h.
The third Monad Law, says, e.g., that
getLine >>= \ n -> putStrLn n >>= return
is equivalent to
getLine >>= putStrLn >>= return,
and the second Monad Law says that this is in turn equivalent to
getLine >>= putStrLn.
Control Structures
Thinking of monads as actions, let's look at structured action.
The simplest thing one can do with a set of actions is put them in sequence. The command for this collects a list of monad actions into a monad action list (defined in Control.Monad.State
):
sequence :: Monad m => [m a] -> m [a]
sequence [] = return []
sequence (x:xs) = x >>= \v ->
sequence xs >>= \vs ->
return (v:vs)
In do notation:
sequence :: Monad m => [m a] -> m [a]
sequence [] = return []
sequence (x:xs) = do v <- x
vs <- sequence xs
return (v:vs)
From GHC 7.10 onwards this was moved to Data.Traversable
since it works not just on lists but on all Traversable things.
Example
Suppose solveNs
is a function that takes a list of nodes and collects all solutions for those nodes (found, e.g., by exploring a search tree) in a list. Then its type is [Node] -> [Node]
, for some appropriate definition of Node
. Let showNode
be a monadic function for displaying nodes on the screen. Its type is Node -> IO ()
. Then to solve a list of nodes, and show the solutions on screen, we can use:
solveShowNs :: [Node] -> IO[()]
solveShowNs = sequence . fmap showNode . solveNs
Another example
*FSA4> sequence [getLine,getLine] >>= print
Jan
van Eijck
["Jan","van Eijck"]
Action iteration can be expressed as a for loop. This is defined in Control.Monad.State
as:
forM :: Monad m => [a] -> (a -> m b) -> m [b]
forM xs f = sequence . map f xs
Imperative programming:
*FSA4> forM [1..10] print
1
2
3
4
5
6
7
8
9
10
[(),(),(),(),(),(),(),(),(),()]
Or, if we are not interested in the result of the loop body:
*FSA4> forM_ [1..10] print
1
2
3
4
5
6
7
8
9
10
Definition of forM_
:
forM_ :: (Monad m) => [a] -> (a -> m b) -> m ()
forM_ xs f = sequence_ (map f xs)
And the version of sequence
that throws away the result:
sequence_ :: (Monad m) => [m a] -> m ()
sequence_ [] = return ()
sequence_ (x:xs) = x >> sequence_ xs
Function Application Within a Monad
Suppose we are processing inside a monad, and we need to apply a non-monadic function, say a function that maps character strings to uppercase, map toUpper
, where toUpper
is defined in the module Data.Char
. Then this is how to do it:
*FSA4> liftM (map toUpper) getLine >>= putStrLn
jan
JAN
The function liftM
turns the string operation map toUpper
into a monadic function.
The following are equivalent:
liftM (map toUpper) getLine
and
map toUpper `liftM` getLine.
This shows that liftM
can be used as the monadic version of $
. Where $
is the operation for application of pure functions, liftM
expresses function application within a monad.
Definition of liftM
:
liftM :: Monad m => (a -> b) -> m a -> m b
liftM f m = do { x <- m; return (f x) }
Alternative version, in bind
notation:
liftM :: Monad m => (a -> b) -> m a -> m b
liftM f m = m >>= \ x -> return (f x)
Another alternative:
liftM :: Monad m => (a -> b) -> m a -> m b
liftM f m = m >>= return . f
There are also versions liftM2
, liftM3
, liftM4
, liftM5
, for functions with 2, 3, 4, 5 arguments.
Here is liftM2
:
liftM2 :: Monad m =>
(a -> b -> c) -> m a -> m b -> m c
liftM2 f k m = k >>= \ x ->
m >>= \ y ->
return (f x y)
This allows to define function application within a monad:
ap :: Monad m => m (a -> b) -> m a -> m b
ap = liftM2 id
To understand this definition, note that in the call liftM2 id
, id
will get instantiated as the identity function of type (a -> b) -> a -> b
. This gives liftM2
the type (a -> b) -> (a -> b) -> m (a -> b) -> m a -> m b
.
In the definition, x
will be a function of type a -> b
, id x
will be the same function, and id x y
means application of x
to y
. This shows that an equivalent definition, perhaps easier to comprehend, is possible:
ap :: Monad m => m (a -> b) -> m a -> m b
ap = liftM2 ($)
Thus, ap
is indeed the lifted monadic version of function application.
Examples of using ap
> [(+ 1), (+ 2)] `ap` [1, 2, 3]
[2, 3, 4, 3, 4, 5]
> Just (+ 1) `ap` Just 1
Just 2
> Just (*) `ap` (Just 2) `ap` (Just 3)
Just 6
For another use of liftM2
, consider the number lookup plus processing example again. Here is a more abstract version in terms of liftM2
:
> process' m n = liftM2 (+)
> (lookup m table) (lookup n table)
Notice that sequence
can be rewritten in terms of liftM
, as follows:
sequence :: Monad m => [m a] -> m [a]
sequence = foldr (liftM2 (:)) (return [])
And the version that throws away the results can be defined in terms of foldr
and (>>)
:
sequence_ :: Monad m => [m a] -> m ()
sequence_ = foldr (>>) (return ())
Conditional execution
The when
for conditional execution is also defined in Control.Monad
:
when :: Monad m => Bool -> m () -> m ()
when p x = if p then x else return ()
The reverse of when
:
unless :: Monad m => Bool -> m () -> m ()
unless p x = if p then return () else x
An infinite loop
forever :: Monad m => m a -> m b
forever a = let a' = a >> a' in a'
Generalization of filter
to monads:
filterM :: Monad m => (a -> m Bool) -> [a] -> m [a]
filterM _ [] = return []
filterM p (x:xs) = do
flg <- p x
ys <- filterM p xs
return (if flg then x:ys else ys)
Fold for monads:
foldM :: Monad m =>
(a -> b -> m a) -> a -> [b] -> m a
foldM _ a [] = return a
foldM f a (x:xs) = f a x >>= \fax -> foldM f fax xs
And the version that throws away the result:
foldM_ :: Monad m =>
(a -> b -> m a) -> a -> [b] -> m ()
foldM_ f a xs = foldM f a xs >> return ()
State as a Monad
> newtype StateMonad s a = SM (s -> (a,s))
Declare this an instance of Functor and Applicative:
> instance Functor (StateMonad s) where
> -- fmap :: (a -> b) -> StateMonad s a -> StateMonad s b
> fmap f (SM x) = SM (\ s -> let (a,t) = x s in (f a, t))
>
> instance Applicative (StateMonad s) where
> -- pure :: a -> StateMonad s a
> pure a = SM (\ s -> (a,s))
> -- (<*>) :: StateMonad s (a -> b) -> StateMonad s a -> StateMonad s b
> (SM xf) <*> (SM xa) = SM (\ s -> let (f ,s' ) = xf s
> (a ,s'') = xa s'
> in (f a,s'') )
Declare this an instance of Monad:
> instance Monad (StateMonad s) where
> return a = SM (\ s -> (a,s))
> x >>= f = SM (\s -> let SM x' = x
> (a,s') = x' s
> SM f' = f a
> (b,s'') = f' s'
> in (b,s''))
Functions for fetching and storing values:
> fetch :: StateMonad s s
> fetch = SM (\ s -> (s,s))
>
> store :: s -> StateMonad s ()
> store x = SM (\ _ -> ((),x))
A function to increment a counter.
> tck :: StateMonad Int Int
> tck = do n <- fetch
> store (n+1)
> return n
There is also a predefined class State
, with functions put
and get
defined for it. This gives the following implementation of the ticking process:
> tick :: State Int Int
> tick = do n <- get
> put (n+1)
> return n
Monads and Parsing
Monadic Parser Combinators (Graham Hutton, Erik Meijer cs). See Monadic Parsing in Haskell.
> newtype Parser a = Parser { parse :: String -> [(a,String)] }
Parsers as Functors
> instance Functor Parser where
> fmap f (Parser p) = Parser (\cs -> [(f a, b) | (a, b) <- p cs])
Parsers as Applicatives
> instance Applicative Parser where
> pure x = Parser (\ cs -> [(x,cs)])
> (Parser p1) <*> (Parser p2) =
> Parser (\cs -> [(f a, cs2) | (f, cs1) <- p1 cs,
> (a, cs2) <- p2 cs1])
Parsers as Monads
> instance Monad Parser where
> return = pure
> p >>= f = Parser (\cs ->
> concat [parse (f a) cs' | (a,cs') <- parse p cs ])
And so on ...
Further Reading
The list of monad tutorials on internet is almost endless ...