FSA, Week4: Action and Interaction

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.


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.


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
 *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
 *FSA4> 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)
 *FSA4> join 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
 *FSA4> process 3 5
 Just 152
 *FSA4> process 0 3
 *FSA4> process 3 200

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]

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

Since return for lists is the function \ x -> [x], the following is equivalent:

 *FSA4> [1,2,3] >>= \ x -> [x]

Let's make a few variations on x -> [x] and see what we get:

 *FSA4> [1,2,3] >>= \ x -> [x,x]
 *FSA4> [1,2,3] >>= \ x -> [x,x,x]
 *FSA4> [1,2,3] >>= \ x -> [x,x,x,x]
 *FSA4> [[1],[2,3],[4]] >>= id

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]

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'
 *FSA4> do putStrLn "x" ; putStrLn "y" ; putStrLn '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)
 "hello jan"
 *FSA4> do x <- getLine; putStrLn ("hello "++x)
 "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

    *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]
    *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
 *FSA4> getRandomInt 20
 *FSA4> getRandomInt 20
 *FSA4> getRandomInt 20

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
 *FSA4> genIntList
 *FSA4> genIntList
 *FSA4> genIntList
 *FSA4> genIntList

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.

The Monad Laws

The Monad Laws state that return and bind should behave like this:

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.


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
 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 

Or, if we are not interested in the result of the loop body:

 *FSA4> forM_ [1..10] print 

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

The function liftM turns the string operation map toUpper into a monadic function.

The following are equivalent:

 liftM (map toUpper) getLine


 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 ...