Monads

What

Metaprogramming over boxed types

For our purposes, a "monad" is ANY "boxed type" that

Has some specific methods

Those methods follow ~the same algebraic laws as "+" and "*"

Examples

Iterable<T>

Map<K,T>.keySet(), etc...

List<T>

...

Option<T>

Challenges

(Opaque) Haskell syntax

Inordinate and excessive use of mathematical jargon

(If you don't get this you're clearly not smart enough to play with us.)

Differing names for the same concept

Point vs. Bind

fmap vs. map (What's the dif? Is there any?)

Different notations for describing exactly the same thing!

Why?

Because you might like to operate on boxed types without explicitly unboxing

Because you might like to transform the elements inside one box into different values stored in another box of the same or different type

Because you might like to copy the elements inside one box into another box of the same or different type

Because you'd like to preserve reasonable algebraic properties over those operations

Because it would be *really* nice if all of these operations could run in parallel, automatically

How

Reimplement the dot operator ?!?!

The traditional dot operator...

// How dot really works

def dotOperator(method : (M<A> -> M<B>), receiver : M<A>) : M<B> = { ... }

def invoke (method : (M<A> -> M<B>), receiver : M<A>) : M<B> = { ... }

A Monadic dot operator: The method the dot operator accepts has to have a particular (generic) signature

// How dot really works

def dotOperator(method : (M<A> -> M<B>), receiver : M<A>) : M<B> = { ... }

def invoke (method : (M<A> -> M<B>), receiver : M<A>) : M<B> = { ... }

// What if the dot operator knew how to unpack an M<A>?

// (Exercise: Why do we care that the operator knows how to unpack M<A>?)

def monadicDotOperator(method : (A -> M<B>), receiver : M<A>) : M<B> = { ... }

// Now let's add the FP jargon back in ;)

def flatmap (method : (A -> M<B>), receiver : M<A>) : M<B> = { ... }

// or:

def bind (method : (A -> M<B>), receiver : M<A>) : M<B> = { ... }

The "operator": Traditionally called either "bind" or "flatmap"

The implementation must obey certain algebraic properties

Specifically, properties similar to "+", or of addition

Identity

Associativity

Putting it all together...

An boxed type with...

A constructor

Traditionally: Unit or something that behaves like a 1-arg constructor

bind/flatmap

That obeys the monadic laws

Informally

The Monadic Laws--Expressed informally:

1) If you unbox a value and box it again, you'll get "the same"** monad as the original.

2) If you map/flatmap a function f over a boxed value v, the result is "the same" as if you'd computed f(v) directly.

3) Associativity works. If you chain flatmap operations together, executing "the second two operations first" results in the same thing as executing them in order.

** "The same" in a monadic context means that #equals and #hashCode say that the objects are the same, not necessarily that the values are literally the same reference or that they are internally implemented identically.

Formally

Formally:

1) m flatmap unit === m

2) unit(x) flatmap f === f(x) === x.f()

3) m flatmap g flatmap f === m flatmap {x => g(x) flatmap f }

(Remember: Unit is the generic name for a monad's 1-arg constructor)

Thanks to James Iry's blog series for this formulation of the Monad Laws.

Informally:

1) If you unbox a value and box it again, you'll get "the same" monad as the original.

2) If you map/flatmap a function f over a boxed value v, the result is "the same" as if you'd computed f(v) directly.

3) Associativity works. If you chain flatmap operations together, executing the second two operations first results in the same thing as executing them in order.

** "The same" in a monadic context means that #equals and #hashCode say that the objects are the same, not necessarily that the values are literally the same reference or that they are internally implemented identically.

In Scala, also: map

Bonus

For comprehensions work automatically over your monad implementations

Meaning / implementation in Scala

Scala's for comprehensions

Haskell's "do-notation" is a syntax to write monad based program fragments:

do

x <- m1

y <- m2

return (x + y)

In Scala, this would look like this:

for(val x <- m1 m1.flatMap { x => m1.flatMap { x =>

val y <- m2) ==becomes==> m2.map { y => i.e. =!= m1.flatMap { x =>

yield {x + y} x+y }} unit (x+y) }}

(From http://lampwww.epfl.ch/~emir/bqbase/2005/01/20/monad.html)

Exercises

Implement invoke using Java reflection API calls to mimic bind/flatmap

Implement bind/flatmap over Iterable<T>

public interface F<A,B> {

B f(A domain);

}

public class IterableMonad {

public static <A, B> Iterable<B> flatmap(Iterable<A> receiver, F<A, Iterable<B>> f) {

}

}

Implement map over Iterable<T>

Read the nodes clockwise, starting with "What"

By David Orme <djo@coconut-palm-software.com>