Transcript Monads

Monads
foo1

Method to print a string, then return its length:

scala> def foo1(bar: String) = {
|
println(bar)
|
bar.size
| }
foo1: (bar: String)Int

scala> foo1("Hello")
Hello
res0: Int = 5
2
foo2

Here’s the same method, but replacing each expression
with an anonymous function:

scala> def foo1(bar: String) = {
|
(() => println(bar))()
|
(() => bar.length)()
| }
foo1: (bar: String)Int

scala> foo2("Hello")
Hello
res1: Int = 5
3
andThen does sequencing

scala> def double(x: Int) = 2 * x
double: (x: Int)Int
scala> def triple(x: Int) = 3 * x
triple: (x: Int)Int
scala> ((double _) andThen (triple _))(5)
res4: Int = 30

scala> def upper(s: String) = s.toUpperCase
upper: (s: String)String
scala> def addXs(s: String) = "x" + s + "x"
addXs: (s: String)String
scala> ((upper _) andThen (addXs _))("Hello")
res10: String = xHELLOx
4
andThen applied to foo

Consider this form:


def foo(bar: String) = {
({ () => println(bar) } andThen { () => bar.length })()
}
The above almost works…



is not defined for 0-argument functions
Basically, what this achieves is sequencing in a purely
functional manner
In pure functions, there is no concept of sequencing
andThen
5
Thing

Compare:

def foo(i: Int) = i + 1
val a = 1
val b = foo(a)

With:

case class Thing[+A](value: A)
val a = Thing(1)
val b = Thing(2)
def foo(i: Int) = Thing(i + 1)
val a = Thing(1)
val b = foo(a.value)

The difference is that in the second, the value is “wrapped” in a
Thing container
6
Monads as wrappers

A monad consists of three things:




A type constructor M
A bind operation,
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
A return operation, return :: (Monad m) => a -> m a
Is Thing a monad?



It has a type constructor, Thing
It has a return operation, Thing(i)
Let’s give it a bind operation:
case class Thing[+A](value: A) {
def bind[B](f: A => Thing[B]) = f(value)
}
7
The Thing monad

Here’s what we had before:

scala> val a = Thing(1)
a: Thing[Int] = Thing(1)
scala> val b = foo(a.value)
b: Thing[Int] = Thing(2)

Here’s what we have now:

scala> val a = Thing(1)
a: Thing[Int] = Thing(1)
scala> val b = a bind foo
b: Thing[Int] = Thing(2)

We have additional syntax, but really, nothing’s
changed
8
The monad pattern


Any time you start with something which you pull apart and use
to compute a new something of that same type, you have a
monad.
val a = Thing(1)


The first thing is that I can wrap up a value inside of a new Thing. Objectoriented developers might call this a “constructor”. Monads call it “the unit
function”. Haskell calls it “return” (maybe we shouldn’t try to figure out
that one just yet).
a bind { i => Thing(i + 1) }

We also have this fancy bind function, which digs inside our Thing and
allows a function which we supply to use that value to create a new Thing.
Scala calls this function “flatMap”. Haskell calls it “>>=”. …What’s
interesting here is the fact that bind is how you combine two things
together in sequence.
Directly quoted from www.codecommit.com/blog/
9
bind == flatMap


Scala’s for expression is translated into map, flatMap,
and withFilter operations
Multiple generators lead to a flatMap


for (x <- expr1; y <- expr2; seq) yield expr3
gets translated to
expr1.flatMap(x => for (y <- expr2; seq) yield
expr3)
Repeated use of flatMap will change
List[List[List[items]]] into just List[items]
10
flatMap


The flatMap method is like Map, but removes one level of nesting from a sequence

scala> List(2, 3, 4, 5) map (x => List(x, x * x, x * x * x))
res21: List[List[Int]] = List(List(2, 4, 8), List(3, 9, 27),
List(4, 16, 64), List(5, 25, 125))

scala> List(2, 3, 4, 5) flatMap (x => List(x, x * x, x * x * x))
res22: List[Int] = List(2, 4, 8, 3, 9, 27, 4, 16, 64, 5, 25, 125)
Used with a sequence of Option, flatMap effectively reduces Some(x) to x,
and entirely deletes None

scala> List(1, -1, 2, 4, -5, 9) flatMap (root(_))
res17: List[Double] = List(1.0, 1.4142135623730951, 2.0, 3.0)
11
Using flatMap

scala> for (v <- List(1, 2, 3, -1, 4)) {
| val Some(rootOfV) = root(v)
| println(rootOfV)
| }
1.0
1.4142135623730951
1.7320508075688772
scala.MatchError: None (of class scala.None$)

scala> for (v <- List(1, 2, 3, -1, 4) flatMap (root(_))) println(v)
1.0
1.4142135623730951
1.7320508075688772
2.0
12
Option

A value of type Option[T] can be either Some[value] or
None, where value is of type T

scala> def root(x: Double): Option[Double] =
| if (x >= 0) Some(math.sqrt(x)) else None
root: (x: Double)Option[Double]

scala> root(10.0)
res14: Option[Double] = Some(3.1622776601683795)

scala> root(-5.0)
res15: Option[Double] = None
13
bind for Option

sealed trait Option[+A] {
def bind[B](f: A => Option[B]): Option[B]
}

case class Some[+A](value: A) extends Option[A] {
def bind[B](f: A => Option[B]) = f(value)
}

case object None extends Option[Nothing] {
def bind[B](f: Nothing => Option[B]) = None
}
14
A “functional” println

def foo(bar: String,
stdout: Vector[String]) = {
val stdout2 = println(bar, stdout)
(bar.length, stdout2)
}
def println(str: String,
stdout: Vector[String]) =
stdout + str


Functional input is trickier—we won’t go there
Now let’s do this for everything!
15
Maintaining state

A purely functional language has no notion of “state”
(or time, or change…)



Everything relevant to a function is in its parameters
Therefore, a function that “changes state” must be called
recursively with different parameters
Consider an adventure game



State includes the location of each object and the location of
the player—this is easily done with a Map
The state usually includes other information (is the dragon
alive?)—we can put this in a tuple along with the Map
Player’s actions can be implemented with a function that takes
a State and computes a new State—that is, a monad
16
Life, the Universe, and Everything

Passing around the entire “state of the universe” in
parameters seems excessive, but…



Typically a very large proportion of the information is
immutable, and need not be part of the state
You have to depend on the quality of the implementation of
persistent data structures
Scala has a specific State monad

I haven’t explored this, but I’ve read that it’s complicated
17
And then there’s the IO monad…


Haskell’s IO monad is like our earlier “functional”
println, only richer and with a better syntax
Like all monads, it pulls apart some kind of a thing, and
creates a new thing from it




The weird part is, I/O happens along the way
Output doesn’t affect the result
Input does affect the result
The IO monad (1) achieves sequencing, and (2) isolates the
I/O side effects from the rest of the program
18
Formal definition of a monad

A monad consists of three things:




A type constructor M
A bind operation,
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
A return operation, return :: (Monad m) => a -> m a
And the operations must obey some simple rules:

return x >>= f



f x
return just sends its result to the next function
m >>= return

=
=
m
Returning the result of an action is equivalent to just doing the action
do {x <- m1; y <- m2; m3} =
do {y <- do {x <- m1; m2} m3}

>>= is associative
The End

Substantial portions of this talk taken from:
http://www.codecommit.com/blog/
20
Try

scala> import scala.util.{Try, Success, Failure}
import scala.util.{Try, Success, Failure}
scala> def root2(x: Double): Try[Double] =
|
if (x >= 0) Success(math.sqrt(x)) else
|
Failure(new Exception("Imaginary root"))
root2: (x: Double)scala.util.Try[Double]

scala> root2(10)
res28: scala.util.Try[Double] =
Success(3.1622776601683795)

scala> root2(-10)
res29: scala.util.Try[Double] =
Failure(java.lang.Exception: Imaginary root)
21