monads. foo1 method to print a string, then return its length: scala> def foo1(bar: string) = { |...

21
Monads

Upload: posy-carson

Post on 19-Jan-2016

226 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 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>

Monads

Page 2: 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

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")Hellores0: Int = 5

2

Page 3: 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>

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")Hellores1: Int = 5

3

Page 4: 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>

andThen does sequencing scala> def double(x: Int) = 2 * x

double: (x: Int)Int

scala> def triple(x: Int) = 3 * xtriple: (x: Int)Int

scala> ((double _) andThen (triple _))(5)res4: Int = 30

scala> def upper(s: String) = s.toUpperCaseupper: (s: String)String

scala> def addXs(s: String) = "x" + s + "x"addXs: (s: String)String

scala> ((upper _) andThen (addXs _))("Hello")res10: String = xHELLOx

4

Page 5: 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>

andThen applied to foo

Consider this form: def foo(bar: String) = {

({ () => println(bar) } andThen { () => bar.length })()}

The above almost works… andThen 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

5

Page 6: 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>

Thing Compare:

def foo(i: Int) = i + 1

val a = 1val 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

Page 7: 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>

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

Page 8: 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>

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 foob: Thing[Int] = Thing(2)

We have additional syntax, but really, nothing’s changed

8

Page 9: 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>

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. Object-

oriented 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.

9Directly quoted from www.codecommit.com/blog/

Page 10: 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>

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 toexpr1.flatMap(x => for (y <- expr2; seq) yield expr3)

Repeated use of flatMap will change List[List[List[items]]] into just List[items]

10

Page 11: 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>

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

Page 12: 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>

Using flatMap scala> for (v <- List(1, 2, 3, -1, 4)) {

| val Some(rootOfV) = root(v) | println(rootOfV) | }1.01.41421356237309511.7320508075688772scala.MatchError: None (of class scala.None$)

scala> for (v <- List(1, 2, 3, -1, 4) flatMap (root(_))) println(v)1.01.41421356237309511.73205080756887722.0

12

Page 13: 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>

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

Page 14: 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>

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

Page 15: 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>

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

Page 16: 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>

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

Page 17: 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>

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

Page 18: 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>

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

Page 19: 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>

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

Page 20: 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>

The End

Substantial portions of this talk taken from: http://www.codecommit.com/blog/

20

Page 21: 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>

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