Your SlideShare is downloading. ×
The Essence of the Iterator Pattern (pdf)
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Saving this for later?

Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime - even offline.

Text the download link to your phone

Standard text messaging rates apply

The Essence of the Iterator Pattern (pdf)

501
views

Published on

The Essence of the Iterator Pattern (pdf version)

The Essence of the Iterator Pattern (pdf version)

Published in: Technology, Business

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
501
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
22
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Computation FunctorAPPLICATIVE For loop Traverse
  • 2. Computation K[T]A type of A type of valuecomputation
  • 3. ComputationsZero or one Option[T]Zero or more List[T]Later Future[T]Depend on S State[S, T]Ext. effects IO[T]
  • 4. 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)
  • 5. Pointed K[T].point(t)Compute a value
  • 6. 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”))
  • 7. FunctorK[T] map f Use the value
  • 8. Functors mapOption[T] modify the valueList[T] modify the valuesFuture[T] modify laterState[S, T] modify tsIO[T] modify the action
  • 9. ApplicativeBeforegetUser(props: Properties): StringgetPassword(props: Properties): StringgetConnection(user: String, pw: String):Connection = { if (user != null && pw != null) ....}getConnection(getUser(p), getPassword(p))
  • 10. ApplicativeAftergetUser(props: Properties): Option[String]getPassword(props: Properties): Option[String]getConnection(user: String, pw: String):Connection = { if (user != null && pw != null) ....}getConnection(?, ?)
  • 11. Applicativef(a, b)How?f(K[a], K[b])
  • 12. Use Pointedf(a:A, b:B): Cpointfk: K[A => B => C]
  • 13. Applicative K[A => B] <*> K[A] == K[B]Apply the function
  • 14. Applicative K[A => B => C] <*> K[A] <*> K[B] == K[B => C] <*> K[B] ==Currying ftw! K[C]
  • 15. ApplicativeK(f) <*> K(a) <*> K(b)Apply ‘f’ to ‘a’ and ‘b’ “inside” ‘K’
  • 16. ApplicativeK(f) <*> K(a) <*> K(b)Apply ‘f’ to ‘a’ and ‘b’ “inside” ‘K’
  • 17. Applicative OptionSome(getConnection.curried) <*>user(p) <*>password(p)
  • 18. Applicative Option(user(p) <**> password(p))(mkConnection)mkConnection <$> user(p) <*> password(p)
  • 19. Applicative Futurefuture(discount(_,_))) <*>future(amount) <*>future(rate): Future[Double]
  • 20. Applicative ListList(plus1) <*> List(1, 2, 3)List(2, 3, 4)
  • 21. Applicative ListList(plus1, plus2) <*> List(1, 2, 3)== List(2, 3, 4, 3, 4, 5)ratings <*> clients
  • 22. Applicative ZipListList(plus1, plus2, plus3) <*>List(1, 2, 3)== List(1, 4, 6)
  • 23. Applicative Stateval 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) == ?
  • 24. Applicative State current state +1=2 +1=3(add <$> s1 <*> s1)(1) == (3, 5) add 2 previous states +1=2 +1=3(times <$> s1 <*> s1)(1) == (3, 6) multiply 2 previous states
  • 25. Monad, remember?Unitdef unit[A](a: =>A): M[A]Binddef bind[A, B](ma: M[A])(f: A => M[B]): M[B]
  • 26. Monad => ApplicativePointdef point(a: =>A) = Monad[M].unit(a)Applydef <*>[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]
  • 27. The “for” loopval basket = Basket(orange, apple)var count = 0val juices = Basket[Juice]() accumulationfor (fruit <- basket) { count = count + 1 juices.add(fruit.press) “mapping”} same container for the result
  • 28. Traverse Traversabledef traverse(f: A => F[B]): T[A] => F[T[B]] Applicative Same structure
  • 29. Traverse a ListList(x, y, z): List[A]f: A => F[B]
  • 30. Traverse a List Apply ‘f’ to ‘z’F(::) <*> F(z) <*> F(Nil)“Rebuild” the list F(z :: Nil)
  • 31. Traverse a ListF(::) <*> F(y) <*> F(z :: Nil) F(y :: z :: Nil)F(::) <*> F(x) <*> F(y::z::Nil) F(x :: y :: z :: Nil)
  • 32. Traverse a Binary Tree f x y zx x y z y z y z
  • 33. `sequence`def sequence[F: Applicative]: T[F[A]] => F[T[A]] = traverse(identity)
  • 34. `sequence`Execute concurrently?val examples: Seq[Example] = Seq(e1, e2, e3) Sequence of promisesval executing: Seq[Promise[Result]] = examples.map(e => promise(e.execute))val results: Promise[Seq[Result]] = executing.sequence Promise of a sequence
  • 35. Measure with Monoidstrait Monoid[A] { val zero: A; def append(a: A, b: A): A}def measure[T: Traversable, M : Monoid] (f: A => M): T[A] => MCount elements: Int MonoidAccumulate elements: List Monoid
  • 36. `measure`def measure[T: Traversable, M : Monoid] (f: A => M) = traverse(a => f(a))
  • 37. `Const` “Phantom “ typecase class Const[M, +A](value: M)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))}
  • 38. Applicative => MonadUnitdef unit[A](a: =>A) = Const(Monoid[M].zero)Binddef bind[A, B](ma: Const[M, A]) (f: A => Const[M, B]) ==> but no value `a: A` to be found!
  • 39. `measure`Sum up all sizesdef sumSizes[A : Size](seq: Seq[A]) = measure(a => Size[A].size(a))(seq)Collect all sizesdef collectSizes[A : Size](seq: Seq[A]) = measure(a => List(Size[A].size(a)))(seq)
  • 40. `contents`def contents[A](tree: Tree[A]): List[A] = measure(a => List(a))(tree) x => List(x, y, z) y z
  • 41. `shape`def shape[A](tree: Tree[A]): Tree[Unit] = map(a => ())(tree) x => . y z . .def map[A, B](f: A => B): T[A] => traverse(a => Ident(f(a))) Identity monad
  • 42. `decompose`def decompose[A](tree: Tree[A]) = (contents(tree), shape(tree)) List(x, y, z) x => y z . . . Not very efficient…
  • 43. 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)
  • 44. `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 ⊗ shapetree.traverse(contentsAndShape)
  • 45. Type indifference One parameter type constructortrait Apply[F[_]] { def <*>[A, B](f: F[A => B]): F[A] => F[B]}List[Int]: Monoid Applicative => Const[List[Int], _]({type l[a]=Const[List[Int], a]})#l
  • 46. Type indifference Anonymous type ({type l[a]=Const[List[Int], a]})#lType member({type l[a]=Const[List[Int], a]})#lType projection({type l[a]=Const[List[Int], a]})#ltype ApplicativeProduct =({type l[a]=Product[Const[List[A],_],Ident[_],a]})#l
  • 47. Type indifference Measuredef measure[M : Monoid](f: T => M): M = traverse(t => Monoid[M].unit(f(t))).valueFor real…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
  • 48. `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.toStringtree.collect(count, map).apply(0)  (2, Bin(Leaf("1"), Leaf("2")))
  • 49. `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 "+p2tree.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")))
  • 50. EIP `measure`Map and countdef measure[F[_] : Applicative, A, B] (f: F[B], g: A => C): T[A] => F[C]val crosses = modify((s: String) => s+"x")val map = (i: Int) => i.toStringtree.measure(crosses, map).apply("")("xxx", Bin(Leaf("1"), Bin(Leaf("2"), Leaf("3"))))
  • 51. Traversals mapped depend state depend on function map element create state on state elementcollect X X Xdisperse X X Xmeasure X Xtraverse X X X Xreduce X XreduceConst Xmap X
  • 52. Quizzdef 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?
  • 53. 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}
  • 54. Compositionval results = new ListBufferfor (a <- as) { val currentSize = a.size total += currentSize results.add(total)}F1 (map) then F2 (sum) F2 [F1[_]] => Applicative?
  • 55. `assemble`Shape + content => assembleddef assemble[F[_] : Applicative, A]: (f: F[Unit], g: List[A]): T[A] => F[A]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)
  • 56. `assemble`def takeHead: State[List[B], Option[B]] = state { s: List[B] => s match { case Nil => (Nil, None) case x :: xs => (xs, Some(x)) } } F1: Option[_] An element to insertF2 :State[List[A], _] the rest of the listF2 [F1]: State[List[A], Option[_]] An applicative
  • 57. `assemble`def assemble[F[_] : Applicative, A] (f: F[Unit], list: List[A]) = traverse(takeHead).apply(list)
  • 58. Monadic compositionM : Monadval f: B => M[C]val g: A => M[B]val h: A => M[C] = f • gFusion?traverse(f) • traverse(g) == traverse(f • g)
  • 59. Monadic compositionYes if the Monad is commutative val xy = for { val yx = for { x <- (mx: M[X]) y <- (my: M[Y]) xy == yx y <- (my: M[Y]) x <- (mx: M[X]) } yield (x, y) } yield (x, y)State is *not* commutativeval 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))
  • 60. Applicative composition vs Monadic compositionNot 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]]
  • 61. Monadic composition: conjectureCommutative 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
  • 62. Monadic composition: conjecture Commutative functions => fusionSeq(1,2,3).traverse(plus2 ∎ plus1) == 10Seq(1,2,3).traverse(plus2) ∎ Seq(1,2,3).traverse(plus1) == 10 Not commutative functions => no fusionSeq(1,2,3).traverse(times2 ∎ plus1) == 22Seq(1,2,3).traverse(times2) ∎ Seq(1,2,3).traverse(plus1) == 32