Monads

CIS 194 Week 12
8 April 2013

Suggested reading:

Motivation

Over the last couple of weeks, we have seen how the Applicative class allows us to idiomatically handle computations which take place in some sort of “special context”—for example, taking into account possible failure with Maybe, multiple possible outputs with [], consulting some sort of environment using ((->) e), or construct parsers using a “combinator” approach, as in the homework.

However, so far we have only seen computations with a fixed structure, such as applying a data constructor to a fixed set of arguments. What if we don’t know the structure of the computation in advance – that is, we want to be able to decide what to do based on some intermediate results?

As an example, recall the Parser type from the homework, and assume that we have implemented Functor and Applicative instances for it:

newtype Parser a = Parser { runParser :: String -> Maybe (a, String) }
instance Functor Parser where
  ...

instance Applicative Parser where
  ...

Recall that a value of type Parser a represents a parser which can take a String as input and possibly produce a value of type a, along with the remaining unparsed portion of the String. For example, a parser for integers, given as input the string

"143xkkj"

might produce as output

Just (143, "xkkj")

As you saw in the homework, we can now write things like

data Foo = Bar Int Int Char

parseFoo :: Parser Foo
parseFoo = Bar <