the essence of the iterator pattern (pdf)

64

Upload: eric-torreborre

Post on 10-May-2015

537 views

Category:

Technology


2 download

DESCRIPTION

The Essence of the Iterator Pattern (pdf version)

TRANSCRIPT

Page 1: The Essence of the Iterator Pattern (pdf)
Page 2: The Essence of the Iterator Pattern (pdf)

Computation Functor

APPLICATIVE For loop Traverse

Page 3: The Essence of the Iterator Pattern (pdf)

Computation

K[T]

A type of

computation

A type of value

Page 4: The Essence of the Iterator Pattern (pdf)

Computations

Option[T] Zero or one

List[T] Zero or more

Future[T] Later

State[S, T] Depend on S

IO[T] Ext. effects

Page 5: The Essence of the Iterator Pattern (pdf)

Create computations?

Option[T] Some(t)

List[T] List(t)

Future[T] future(t)

State[S, T] state(s => (s, t))

IO[T] IO(t)

Page 6: The Essence of the Iterator Pattern (pdf)

Pointed

K[T].point(t)

Compute a value

Page 7: The Essence of the Iterator Pattern (pdf)

Use computations?

Option[T] Some(2)

List[T] List(1, 2)

Future[T] future(calculate)

State[S, T] state(s => (s, s+1))

IO[T] IO(println(“hello”))

Page 8: The Essence of the Iterator Pattern (pdf)

Functor

K[T] map f

Use the value

Page 9: The Essence of the Iterator Pattern (pdf)

Functors map

Option[T] modify the value

List[T] modify the values

Future[T] modify later

State[S, T] modify ts

IO[T] modify the action

Page 10: The Essence of the Iterator Pattern (pdf)

Applicative

getUser(props: Properties): String

getConnection(user: String, pw: String):

Connection = {

if (user != null && pw != null)

....

}

Before

getPassword(props: Properties): String

getConnection(getUser(p), getPassword(p))

Page 11: The Essence of the Iterator Pattern (pdf)

Applicative

getUser(props: Properties): Option[String]

getConnection(user: String, pw: String):

Connection = {

if (user != null && pw != null)

....

}

After

getPassword(props: Properties): Option[String]

getConnection(?, ?)

Page 12: The Essence of the Iterator Pattern (pdf)

Applicative

f(a, b)

f(K[a], K[b])

How?

Page 13: The Essence of the Iterator Pattern (pdf)

Use Pointed

f(a:A, b:B): C

fk: K[A => B => C]

point

Page 14: The Essence of the Iterator Pattern (pdf)

Applicative

K[A => B] <*> K[A]

Apply the function

==

K[B]

Page 15: The Essence of the Iterator Pattern (pdf)

Applicative

K[A => B => C] <*>

K[A] <*> K[B]

Currying ftw!

==

K[B => C] <*> K[B]

==

K[C]

Page 16: The Essence of the Iterator Pattern (pdf)

Applicative

K(f) <*> K(a) <*> K(b)

Apply ‘f’ to ‘a’ and ‘b’ “inside” ‘K’

Page 17: The Essence of the Iterator Pattern (pdf)

Applicative

K(f) <*> K(a) <*> K(b)

Apply ‘f’ to ‘a’ and ‘b’ “inside” ‘K’

Page 18: The Essence of the Iterator Pattern (pdf)

Applicative

Option

Some(getConnection.curried) <*>

user(p) <*>

password(p)

Page 19: The Essence of the Iterator Pattern (pdf)

Applicative

Option

(user(p) <**> password(p))(mkConnection)

mkConnection <$> user(p) <*> password(p)

Page 20: The Essence of the Iterator Pattern (pdf)

Applicative

Future

future(discount(_,_))) <*>

future(amount) <*>

future(rate)

: Future[Double]

Page 21: The Essence of the Iterator Pattern (pdf)

Applicative

List

List(plus1) <*> List(1, 2, 3)

List(2, 3, 4)

Page 22: The Essence of the Iterator Pattern (pdf)

Applicative

List

List(plus1, plus2) <*> List(1, 2, 3)

ratings <*> clients

== List(2, 3, 4, 3, 4, 5)

Page 23: The Essence of the Iterator Pattern (pdf)

Applicative

ZipList

List(plus1, plus2, plus3) <*>

List(1, 2, 3)

== List(1, 4, 6)

Page 24: The Essence of the Iterator Pattern (pdf)

Applicative State

val add = (i: Int) => (j: Int) => i+j

val times = (i: Int) => (j: Int) => i*j

// 0 -> 1, 2, 3, 4

val s1 = modify((i: Int) => i+1)

(add <$> s1 <*> s1)(1) == ?

(times <$> s1 <*> s1)(1) == ?

Page 25: The Essence of the Iterator Pattern (pdf)

Applicative State

(add <$> s1 <*> s1)(1) == (3, 5)

multiply 2 previous states

+1=2 +1=3

current state

add 2 previous states

+1=2 +1=3

(times <$> s1 <*> s1)(1) == (3, 6)

Page 26: The Essence of the Iterator Pattern (pdf)

Monad, remember?

def unit[A](a: =>A): M[A]

def bind[A, B](ma: M[A])(f: A => M[B]): M[B]

Unit

Bind

Page 27: The Essence of the Iterator Pattern (pdf)

Monad => Applicative

def point(a: =>A) = Monad[M].unit(a)

Point

def <*>[A, B](mf: M[A=>B])(ma: M[A]):M[B] =

Monad[M].bind(mf) { f =>

Monad[M].bind(ma) { a =>

f(a) // M[B]

} // M[B]

} // M[B]

Apply

Page 28: The Essence of the Iterator Pattern (pdf)

The “for” loop val basket = Basket(orange, apple)

var count = 0

val juices = Basket[Juice]()

for (fruit <- basket) {

count = count + 1

juices.add(fruit.press)

}

same container for the result

“mapping”

accumulation

Page 29: The Essence of the Iterator Pattern (pdf)
Page 30: The Essence of the Iterator Pattern (pdf)

Traverse

def traverse(f: A => F[B]): T[A] => F[T[B]]

Traversable

Applicative Same structure

Page 31: The Essence of the Iterator Pattern (pdf)

Traverse a List

List(x, y, z): List[A]

f: A => F[B]

Page 32: The Essence of the Iterator Pattern (pdf)

Traverse a List

F(::) <*> F(z) <*> F(Nil)

Apply ‘f’ to ‘z’

“Rebuild” the list

F(z :: Nil)

Page 33: The Essence of the Iterator Pattern (pdf)

Traverse a List

F(::) <*> F(y) <*> F(z :: Nil)

F(y :: z :: Nil)

F(::) <*> F(x) <*> F(y::z::Nil)

F(x :: y :: z :: Nil)

Page 34: The Essence of the Iterator Pattern (pdf)

Traverse a

Binary Tree

x

f

z y

x

y z z y x

z y

Page 35: The Essence of the Iterator Pattern (pdf)

`sequence`

def sequence[F: Applicative]:

T[F[A]] => F[T[A]] =

traverse(identity)

Page 36: The Essence of the Iterator Pattern (pdf)

`sequence`

val executing: Seq[Promise[Result]] =

examples.map(e => promise(e.execute))

val results: Promise[Seq[Result]] =

executing.sequence

val examples: Seq[Example] =

Seq(e1, e2, e3)

Promise of a sequence

Sequence of promises

Execute concurrently?

Page 37: The Essence of the Iterator Pattern (pdf)

Measure with

Monoids

def measure[T: Traversable, M : Monoid]

(f: A => M): T[A] => M

Count elements: Int Monoid

Accumulate elements: List Monoid

trait Monoid[A] {

val zero: A; def append(a: A, b: A): A

}

Page 38: The Essence of the Iterator Pattern (pdf)

`measure`

def measure[T: Traversable, M : Monoid]

(f: A => M) =

traverse(a => f(a))

Page 39: The Essence of the Iterator Pattern (pdf)

`Const`

case class Const[M, +A](value: M)

“Phantom “ type

new Applicative[Const[M, *]] {

def point(a: =>A) = Const(Monoid[M].zero)

def <*>(f: Const[M, A=>B], a: Const[M, A]) =

Const(Monoid[M].append(f.value, a.value))

}

Page 40: The Essence of the Iterator Pattern (pdf)

Applicative => Monad

def unit[A](a: =>A) = Const(Monoid[M].zero)

Unit

def bind[A, B](ma: Const[M, A])

(f: A => Const[M, B]) =

=> but no value `a: A` to be found!

Bind

Page 41: The Essence of the Iterator Pattern (pdf)

`measure`

def sumSizes[A : Size](seq: Seq[A]) =

measure(a => Size[A].size(a))(seq)

Sum up all sizes

def collectSizes[A : Size](seq: Seq[A]) =

measure(a => List(Size[A].size(a)))(seq)

Collect all sizes

Page 42: The Essence of the Iterator Pattern (pdf)

`contents`

def contents[A](tree: Tree[A]): List[A] =

measure(a => List(a))(tree)

x

z y

=> List(x, y, z)

Page 43: The Essence of the Iterator Pattern (pdf)

`shape`

def shape[A](tree: Tree[A]): Tree[Unit] =

map(a => ())(tree)

x

z y

=> .

. .

def map[A, B](f: A => B): T[A] =>

traverse(a => Ident(f(a)))

Identity monad

Page 44: The Essence of the Iterator Pattern (pdf)

`decompose`

def decompose[A](tree: Tree[A]) =

(contents(tree), shape(tree))

Not very efficient…

x

z y

=> .

. .

List(x, y, z)

Page 45: The Essence of the Iterator Pattern (pdf)

Applicative products

case class Product[F1[_], F2[_], A](

first: F1[A], second: F2[A])

F1: Applicative, F2: Applicative def point[A, B](a: => A) =

Product[F1, F2, B](Pointed[F1].point(a),

Pointed[F2].point(a))

def <*>[A, B](f: Product[F1, F2, A => B]) =

(c: Product[F1, F2, A]) =>

Product[F1, F2, B](f.first <*> c.first,

f.second <*> c.second)

Page 46: The Essence of the Iterator Pattern (pdf)

`contents ⊗ shape`

F1 = Const[List[A], *] F2 = Ident[*]

val contents = (a: A) => Const[List[A], Unit](List(a))

val shape = (a: A) => Ident(())

val contentsAndShape:

A => Product[Const[List[A], _], Ident[_], *] =

contents ⊗ shape

tree.traverse(contentsAndShape)

Page 47: The Essence of the Iterator Pattern (pdf)

Type indifference

List[Int]: Monoid Applicative => Const[List[Int], _]

({type l[a]=Const[List[Int], a]})#l

One parameter type constructor trait Apply[F[_]] {

def <*>[A, B](f: F[A => B]): F[A] => F[B]

}

Page 48: The Essence of the Iterator Pattern (pdf)

Type indifference

({type l[a]=Const[List[Int], a]})#l

type ApplicativeProduct =

({type l[a]=Product[Const[List[A],_],Ident[_],a]})#l

Anonymous type

({type l[a]=Const[List[Int], a]})#l

Type member

({type l[a]=Const[List[Int], a]})#l

Type projection

Page 49: The Essence of the Iterator Pattern (pdf)

Type indifference

Measure def measure[M : Monoid](f: T => M): M =

traverse(t => Monoid[M].unit(f(t))).value

def measure[M : Monoid](f: A => M): M =

traverse[(type l[a]=Const[M, a]})#l, A, Any] { t =>

Monoid[M].point(f(t))

}.value

For real…

Page 50: The Essence of the Iterator Pattern (pdf)

`collect`

Accumulate and map def collect[F[_] : Applicative, A, B]

(f: A => F[Unit], g: A => B) = {

traverse { a: A =>

Applicative[F].point((u: Unit) => g(a)) <*> f(a))

}

}

val count = (i: Int) => state((n: Int) => (n+1, ()))

val map = (i: Int) => i.toString

tree.collect(count, map).apply(0)

(2, Bin(Leaf("1"), Leaf("2")))

Page 51: The Essence of the Iterator Pattern (pdf)

`disperse`

Label and map def disperse(F[_] : Applicative, A, B, C]

(f: F[B], g: A => B => C): T[A] => F[T[C]]

val tree = Bin(Leaf(1.1), Bin(Leaf(2.2), Leaf(3.3)))

val label = modify((n:Int) => n+1)

val name = (p1:Double) => (p2:Int) => p1+" node is "+p2

tree.disperse(label, name).apply(0)._2

Bin(Leaf("1.1 node is 1"),

Bin(Leaf("2.2 node is 2"), Leaf("3.3 node is 3")))

Page 52: The Essence of the Iterator Pattern (pdf)

val crosses = modify((s: String) => s+"x")

val map = (i: Int) => i.toString

tree.measure(crosses, map).apply("")

("xxx", Bin(Leaf("1"), Bin(Leaf("2"),

Leaf("3"))))

EIP `measure`

def measure[F[_] : Applicative, A, B]

(f: F[B], g: A => C): T[A] => F[C]

Map and count

Page 53: The Essence of the Iterator Pattern (pdf)

Traversals

function map element create state mapped depend

on state

state depend on

element

collect X X X

disperse X X X

measure X X

traverse X X X X

reduce X X

reduceConst X

map X

Page 54: The Essence of the Iterator Pattern (pdf)

Quizz

def findMatches(divs: Seq[Int], nums: Seq[Int])

findMatches(Seq(2, 3, 4), Seq(1, 6, 7, 8, 9))

=> Seq((2, 6), (3, 9), (4, 8))

With Traverse?

Page 55: The Essence of the Iterator Pattern (pdf)

Quizz

def findMatches(divs: Seq[Int], nums: Seq[Int]) = {

case class S(matches: Seq[(Int, Int)] = Seq[(Int, Int)](),

remaining: Seq[Int])

val initialState = S(remaining = nums)

def find(div: Int) = modify { (s: S) =>

s.remaining.find(_ % div == 0).map { (n: Int) =>

S(s.matches :+ div -> n, s.remaining - n)

}.getOrElse(s)

}

divs.traverse(find).exec(initialState).matches

}

Page 56: The Essence of the Iterator Pattern (pdf)

Composition

val results = new ListBuffer

for (a <- as) {

val currentSize = a.size

total += currentSize

results.add(total)

}

F1 (map) then F2 (sum)

F2 [F1[_]] => Applicative?

Page 57: The Essence of the Iterator Pattern (pdf)

`assemble`

def assemble[F[_] : Applicative, A]:

(f: F[Unit], g: List[A]): T[A] => F[A]

Shape + content => assembled

val shape: BinaryTree[Unit] = Bin(Leaf(()), Leaf(()))

shape.assemble(List(1, 2))

(List(), Some(Bin(Leaf(1), Leaf(2))))

shape.assemble(List(1, 2, 3))

(List(3), Some(Bin(Leaf(1), Leaf(2))))

shape.assemble(List(1))

(List(), None)

Page 58: The Essence of the Iterator Pattern (pdf)

def takeHead: State[List[B], Option[B]] =

state { s: List[B] =>

s match {

case Nil => (Nil, None)

case x :: xs => (xs, Some(x))

}

}

`assemble`

F1: Option[_] An element to insert

F2 :State[List[A], _] the rest of the list

F2 [F1]: State[List[A], Option[_]] An applicative

Page 59: The Essence of the Iterator Pattern (pdf)

`assemble`

def assemble[F[_] : Applicative, A]

(f: F[Unit], list: List[A]) =

traverse(takeHead).apply(list)

Page 60: The Essence of the Iterator Pattern (pdf)

Monadic composition

val f: B => M[C]

val g: A => M[B]

val h: A => M[C] = f • g

M : Monad

Fusion?

traverse(f) • traverse(g) == traverse(f • g)

Page 61: The Essence of the Iterator Pattern (pdf)

Monadic composition

val xy = for {

x <- (mx: M[X])

y <- (my: M[Y])

} yield (x, y)

Yes if the Monad is commutative

State is *not* commutative

val yx = for {

y <- (my: M[Y])

x <- (mx: M[X])

} yield (x, y)

xy == yx

val mx = state((n: Int) => (n+1, n+1))

val my = state((n: Int) => (n+1, n+1))

xy.apply(0) == (2, (1, 2))

yx.apply(0) == (2, (2, 1))

Page 62: The Essence of the Iterator Pattern (pdf)

Applicative composition vs

Monadic composition

Not commutative functions => fusion

Seq(1,2,3).traverse(times2 ⊙ plus1) == 4

State[Int, State[Int, Seq[Int]]]

Seq(1,2,3).traverse(times2) ⊙

Seq(1,2,3).traverse(plus1) == 4

State[Int, Seq[State[Int, Int]]

Page 63: The Essence of the Iterator Pattern (pdf)

Monadic composition:

conjecture

Commutative functions val plus1 = (a: A) => state((n: Int) => (n+1, a))

val plus2 = (a: A) => state((n: Int) => (n+2, a))

val times2 = (a: A) => state((n: Int) => (n*2, a))

plus1 and plus2 are commutative

plus1 and times2 are not commutative:

(0 + 1) * 2 != (0 * 2) + 1

Page 64: The Essence of the Iterator Pattern (pdf)

Commutative functions => fusion

Seq(1,2,3).traverse(plus2 ∎ plus1) == 10 Seq(1,2,3).traverse(plus2) ∎ Seq(1,2,3).traverse(plus1) == 10

Not commutative functions => no fusion Seq(1,2,3).traverse(times2 ∎ plus1) == 22 Seq(1,2,3).traverse(times2) ∎ Seq(1,2,3).traverse(plus1) == 32

Monadic composition:

conjecture