28. The “for” loop
val basket = Basket(orange, apple)
var count = 0
val juices = Basket[Juice]()
accumulation
for (fruit <- basket) {
count = count + 1
juices.add(fruit.press) “mapping”
}
same container for the result
29.
30. Traverse
Traversable
def traverse(f: A => F[B]): T[A] => F[T[B]]
Applicative Same
structure
36. `sequence`
Execute concurrently?
val examples: Seq[Example] =
Seq(e1, e2, e3)
Sequence of promises
val executing: Seq[Promise[Result]] =
examples.map(e => promise(e.execute))
val results: Promise[Seq[Result]] =
executing.sequence
Promise of a sequence
37. Measure with
Monoids
trait Monoid[A] {
val zero: A; def append(a: A, b: A): A
}
def measure[T: Traversable, M : Monoid]
(f: A => M): T[A] => M
Count elements: Int Monoid
Accumulate elements: List Monoid
39. `Const`
“Phantom “ type
case 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))
}
40. Applicative => Monad
Unit
def unit[A](a: =>A) = Const(Monoid[M].zero)
Bind
def bind[A, B](ma: Const[M, A])
(f: A => Const[M, B]) =
=> but no value `a: A` to be found!
41. `measure`
Sum up all sizes
def sumSizes[A : Size](seq: Seq[A]) =
measure(a => Size[A].size(a))(seq)
Collect all sizes
def collectSizes[A : Size](seq: Seq[A]) =
measure(a => List(Size[A].size(a)))(seq)
46. `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)
47. Type indifference
One parameter type constructor
trait 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
48. Type indifference
Anonymous type
({type l[a]=Const[List[Int], a]})#l
Type member
({type l[a]=Const[List[Int], a]})#l
Type projection
({type l[a]=Const[List[Int], a]})#l
type ApplicativeProduct =
({type l[a]=Product[Const[List[A],_],Ident[_],a]})#l
49. Type indifference
Measure
def measure[M : Monoid](f: T => M): M =
traverse(t => Monoid[M].unit(f(t))).value
For 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
50. `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")))
51. `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")))
52. EIP `measure`
Map and count
def 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.toString
tree.measure(crosses, map).apply("")
("xxx", Bin(Leaf("1"), Bin(Leaf("2"),
Leaf("3"))))
53. Traversals
mapped depend state depend on
function map element create state
on state element
collect X X X
disperse X X X
measure X X
traverse X X X X
reduce X X
reduceConst X
map X
55. 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
}
56. 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?
58. `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 insert
F2 :State[List[A], _] the rest of the list
F2 [F1]: State[List[A], Option[_]] An applicative
60. Monadic composition
M : Monad
val f: B => M[C]
val g: A => M[B]
val h: A => M[C] = f • g
Fusion?
traverse(f) • traverse(g) == traverse(f • g)
61. Monadic composition
Yes 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* commutative
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))