UP | HOME

type : Monad

Navigation   notoc

Motivations

Examples

Types   notoc nav

Introduction   notoc

  • Restrict evaluation to a type constructor context
  • The type constructor determines the semantics of the evaluation

A Monad is an abstraction for type constructors of kind * -> *.

Abstraction

pure :: a -> m a
Wrap a value in the monad type m.
map :: (a -> b) -> m a -> m b
Map a function across a monad value.
flatMap :: (a -> m b) -> m a -> m b
Map a monad returning function across a monad value.

Example

The simplest monad instance is the one for Identity.

Identity a
A type that holds a single value of a.
mkIdentity :: a -> Identity a
Construct an Identity.
getIdentity :: Identity a -> a
Retrieve the wrapped value.

The monad instance:

pure :: a -> Identity a
pure = mkIdentity

map :: (a -> b) -> Identity a -> Identity b
map f ia = identity (f (getIdentity ia))

flatMap :: (a -> Identity b) -> Identity a -> Identity b
flatMap f ia = f (getIdentity ia)

Now imagine a computation that concatenates a list of strings then evaluates their length.

concat :: List String -> String
length :: String -> Int

ss = [ "ab", "cd", "ef" ]
s = concat ss
length s
-- => 6

Using Identity the computation would look like this:

map (\s -> length s) (map (\ss -> concat ss) (pure [ "ab", "cd", "ef" ]))
-- => Identity 6

That looks ugly and gains us nothing. What if the function signatures were different?

concat :: List String -> Identity String
length :: String -> Identity Int

flatMap (s -> length s) (flatMap (\ss -> concat ss) (pure [ "ab", "cd", "ef" ]))
-- => Identity 6

Still ugly. All we've done is switch map for flatMap. What if we alias flatMap to an operator, ;?

x ; f = flatMap f x

pure [ "ab", "cd", "ef" ] ; \ss -> concat ss ; \s -> length s
-- => Identity 6

Add newlines and:

pure [ "ab", "cd", "ef" ];
\ss -> concat ss;
\s -> length s
-- => Identity 6

Compare to the initial non-identity code and you can see that Monad gives us what some have called, “programmable statements”.

-- Statements
ss = [ "ab", "cd", "ef" ]
s = concat ss
length s

-- Monadic statements
pure [ "ab", "cd", "ef" ];
\ss -> concat ss;
\s -> length s

Some languages provide syntax sugar for these operations.

-- Haskell and Purescript
do
  ss <- pure [ "ab", "cd", "ef" ]
  s  <- concat ss
  length s
// Scala
for {
  ss <- pure(List("ab", "cd", "ef"))
  s  <- concat(ss)
  l  <- length(s)
}
yield(l)
// C#
from ss in pure(new[] {"ab", "cd", "ef"})
from s  in concat(ss)
from l  in length(s)
select l

So what? All we've achieved so far is another way of writing statements.