the essence of the iterator pattern

64

Upload: eric-torreborre

Post on 10-May-2015

1.697 views

Category:

Technology


2 download

DESCRIPTION

Presentation on the Essence of the Iterator Pattern given at fpsyd

TRANSCRIPT

Page 1: The Essence of the Iterator Pattern
Page 2: The Essence of the Iterator Pattern

Computation

Functor

APPLICATIVE For loopTraverse

Page 3: The Essence of the Iterator Pattern

Computation

K[T]

A type of computation

A type of value

Page 4: The Essence of the Iterator Pattern

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

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

Pointed

K[T].point(t)

Compute a value

Page 7: The Essence of the Iterator Pattern

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

Functor

K[T] map f

Use the value

Page 9: The Essence of the Iterator Pattern

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

Applicative

getUser(props: Properties): String

getConnection(user: String, pw: String): Connection = { if (user != null && pw != null) ....}

BeforegetPassword(props: Properties): String

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

Page 11: The Essence of the Iterator Pattern

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

Applicative

f(a, b)

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

How?

Page 13: The Essence of the Iterator Pattern

Use Pointed

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

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

point

Page 14: The Essence of the Iterator Pattern

Applicative

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

Apply the function

==

K[B]

Page 15: The Essence of the Iterator Pattern

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

Applicative

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

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

Page 17: The Essence of the Iterator Pattern

Applicative

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

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

Page 18: The Essence of the Iterator Pattern

ApplicativeOption

Some(getConnection.curried) <*> user(p) <*> password(p)

Page 19: The Essence of the Iterator Pattern

ApplicativeOption

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

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

Page 20: The Essence of the Iterator Pattern

ApplicativeFuture

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

: Future[Double]

Page 21: The Essence of the Iterator Pattern

ApplicativeList

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

List(2, 3, 4)

Page 22: The Essence of the Iterator Pattern

ApplicativeList

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

ratings <*> clients

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

Page 23: The Essence of the Iterator Pattern

ApplicativeZipList

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

== List(1, 4, 6)

Page 24: The Essence of the Iterator Pattern

Applicative State

val add = (i: Int) => (j: Int) => i+jval times = (i: Int) => (j: Int) => i*j

// 0 -> 1, 2, 3, 4val s1 = modify((i: Int) => i+1)

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

Page 25: The Essence of the Iterator Pattern

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

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

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

The “for” loopval 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
Page 30: The Essence of the Iterator Pattern

Traverse

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

Traversable

Applicative Same structure

Page 31: The Essence of the Iterator Pattern

Traverse a List

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

f: A => F[B]

Page 32: The Essence of the Iterator Pattern

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

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

Traverse a Binary Tree

xf

zy

x

y z zyx

zy

Page 35: The Essence of the Iterator Pattern

`sequence`

def sequence[F: Applicative]: T[F[A]] => F[T[A]] =

traverse(identity)

Page 36: The Essence of the Iterator Pattern

`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

Measure with Monoids

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

Count elements: Int MonoidAccumulate elements: List Monoid

trait Monoid[A] { val zero: A; def append(a: A, b: A): A}

Page 38: The Essence of the Iterator Pattern

`measure`

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

traverse(a => f(a))

Page 39: The Essence of the Iterator Pattern

`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

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

`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

`contents`def contents[A](tree: Tree[A]): List[A] = measure(a => List(a))(tree)

x

zy

=> List(x, y, z)

Page 43: The Essence of the Iterator Pattern

`shape`def shape[A](tree: Tree[A]): Tree[Unit] = map(a => ())(tree)

x

zy

=> .

..

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

Identity monad

Page 44: The Essence of the Iterator Pattern

`decompose`def decompose[A](tree: Tree[A]) = (contents(tree), shape(tree))

Not very efficient…

x

zy

=>.

..

List(x, y, z)

Page 45: The Essence of the Iterator Pattern

Applicative productscase class Product[F1[_], F2[_], A]( first: F1[A], second: F2[A])

F1: Applicative, F2: Applicativedef 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

`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

Type indifference

List[Int]: Monoid Applicative => Const[List[Int], _]({type l[a]=Const[List[Int], a]})#l

One parameter type constructortrait Apply[F[_]] { def <*>[A, B](f: F[A => B]): F[A] => F[B]}

Page 48: The Essence of the Iterator Pattern

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

Type indifference Measuredef 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

`collect`Accumulate and mapdef 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

`disperse`Label and mapdef 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

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

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

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

Quizzdef 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

Compositionval 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

`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

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

`assemble`def assemble[F[_] : Applicative, A] (f: F[Unit], list: List[A]) =

traverse(takeHead).apply(list)

Page 60: The Essence of the Iterator Pattern

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

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

Applicative composition vsMonadic composition

Not commutative functions => fusionSeq(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

Monadic composition:conjecture

Commutative functionsval 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 commutativeplus1 and times2 are not commutative:

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

Page 64: The Essence of the Iterator Pattern

Commutative functions => fusionSeq(1,2,3).traverse(plus2 ∎ plus1) == 10

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

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

Seq(1,2,3).traverse(times2) ∎ Seq(1,2,3).traverse(plus1) == 32

Monadic composition:conjecture