dev* 2014



  • monads are so last millenium.
    We should already know what they are
  • it's useful to know and understand abstractions,
    even those we don't directly need in our everyday life
  • I'll buy you a beer if you find this presentation useful ;)


In addition to it begin useful, it is also cursed and the curse of the monad is that once you get the epiphany, once you understand - "oh that's what it is" - you lose the ability to explain it to anybody.
-- Douglas Crockford


it's not a burrito

a function

In mathematics, a function is a relation between a set of inputs and a set of permissible outputs with the property that each input is related to exactly one output.

						f :: a -> b

familiar with Haskell syntax?

function composition

In mathematics, function composition is the pointwise application of one function to the result of another to produce a third function.

compose :: (b -> c) -> (a -> b) -> (a -> c)
compose g f = \a -> g (f a)
            = g . f
  • "chaining" functions together
  • notice how this enforces an order for the function applications

function application

in mathematics, function application is the act of applying a function to an argument from its domain so as to obtain the corresponding value from its range.

apply :: (a -> b) -> a -> b

what if our values are "boxed", inside:

  • an Option/Optional/Maybe?
  • a Wicket IModel?
  • a JavaScript Promise?
  • a List?
  • ...

noWay :: Bool -> Bool
someValue :: Maybe Bool

noWay someValue -- whoops, won't compile

a functor

In mathematics, a functor is a type of mapping between categories, which is applied in category theory.

just forget that.

  • "something that can be mapped over"
  • a boxed value
  • a value with a context

class Functor f where
  fmap :: (a -> b) -> f a -> f b
now this works:

noWay :: Bool -> Bool
someValue :: Maybe Bool

(fmap noWay) someValue -- hooray!
  • generalizes function application to work with boxed values
  • you probably shouldn't think of them as boxes.
    or maybe you should.
    I don't know.
  • there's so little structure that the abstraction stays simple

what if our function takes more parameters?

orElse :: Bool -> Bool -> Bool

(fmap orElse) :: Maybe Bool -> Maybe (Bool -> Bool) -- whoops...

return value wrapped inside the container,
need something capable of handling this

an applicative

class Applicative f where
  pure :: a -> f a
  (<*>) :: f (a -> b) -> f a -> f b

notice how the signature is just what we needed

now this works:

orElse :: Bool -> Bool -> Bool
someValue :: Maybe Bool

(pure orElse) <*> someValue <*> someValue -- hooray!
  • b can be a function, so this can be applied multiple times
  • does not say anything about the order of execution,
    so inherently parallelizable
  • generalizes boxed function application to work
    with functions of arity > 1

what if we want to interact with the box?

that is, affect the execution based on computed values?

that is, determine execution based on context?

a monad

class Monad m where
  return :: a -> m a
  (>>=) :: m a -> (a -> m b) -> m b

we have a wrapped value, and we add "actions" to it one by one

(return 1) >>= (\one -> return (one + 1)) >>= (\two -> return (two + 1)) -- and so on...

notice how this enforces the order of execution


we can change the order of arguments:

(>>=) :: m a -> (a -> m b) -> m b
(=<<) :: (a -> m b) -> m a -> m b

now the first part (the initial monadic value) can be given last:

(\one -> return (one + 1) >>= (\two -> return (two + 1))) =<< (return 1)

simplify syntax:

(a -> m b >>= (b -> m c)) =<< m a

compare to function composition,
whose arguments may as well be interchanged:

(.) :: (b -> c) -> (a -> b) -> (a -> c)
(>>>) :: (a -> b) -> (b -> c) -> (a -> c)
(a -> b) >>> (b -> c) $ a

monad generalizes function composition
to work with functions returning boxed values


Lifting is a concept which allows you to transform a function into a corresponding function within another (usually more general) setting.

functor/applicative/monad can be thought of as
an alternative way to apply functions

apply :: (a -> b) -> a -> b
fmap  :: (a -> b) -> f a -> f b
(<*>) :: f (a -> b) -> f a -> f b
(=<<) :: (a -> m b) -> m a -> m b

or a function can be thought to be lifted to another context

fmap   :: (a -> b) -> (f a -> f b)
liftA2 :: (a -> b -> c) -> (f a -> f b -> f c)  -- and liftA, liftA3, ...
liftM2 :: (a -> b -> c) -> (m a -> m b -> m c)  -- and liftM, liftM3, ...


  • binding actions to a Monad one after another while retaining all intermediate variables in scope, is a pattern also known as callback hell
  • using a common abstraction throughout a language lets us add some syntactic sugar to ease the pain
  • in Haskell that sugar is the do-notation, which transforms the callback-tree to an imperative-looking list of actions

anyway, it's just syntax


all these concepts must satisfy certain laws to ensure they are well behaved

we will not go there now =)

Monads and IO in Haskell?

Monads have nothing to do with IO

...but IO needs the order of execution, which happens to be just the concept that a monad can provide

See for more info

going further

class Functor f where
  fmap :: (a -> b) -> f a -> f b

class Applicative f where
  pure :: a -> f a
  (<*>) :: f (a -> b) -> f a -> f b

class Monad m where
  return :: a -> m a
  (>>=) :: m a -> (a -> m b) -> m b -- or: =<< :: (a -> m b) -> m a -> m b

apply ::   (a -> b) -> a -> b
fmap  ::   (a -> b) -> f a -> f b
(<*>) :: f (a -> b) -> f a -> f b
=<<   :: (a -> m b) -> m a -> m b

anything missing?

??    :: (w a -> b) -> w a -> w b
  • YES, there is!
  • it's called a comonad
  • it about push (monad) versus pull (comonad)
  • not explaining here what it is since I still lack the intuition

there's still A LOT more to learn.

go learn!

thank you.