Simplicity in composition

Simplicity in composition

Fb8e986500c5059b2a6c0b2184bb0faf?s=128

Adelbert Chang

September 18, 2017
Tweet

Transcript

  1. Simplicity in composition Adelbert Chang @adelbertchang Scala World 2017 Adelbert

    Chang (@adelbertchang) Simplicity in composition Scala World 2017 1 / 67
  2. Composition A: type (set) of values Adelbert Chang (@adelbertchang) Simplicity

    in composition Scala World 2017 2 / 67
  3. Composition A: type (set) of values ⊕: A × A

    → A Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 2 / 67
  4. Composition A: type (set) of values ⊕: A × A

    → A 1A : identity for ⊕ Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 2 / 67
  5. Composition A: type (set) of values ⊕: A × A

    → A 1A : identity for ⊕ (x ⊕ y) ⊕ z = x ⊕ (y ⊕ z) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 2 / 67
  6. Composition A: type (set) of values ⊕: A × A

    → A 1A : identity for ⊕ (x ⊕ y) ⊕ z = x ⊕ (y ⊕ z) x = x ⊕ 1A = 1A ⊕ x Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 2 / 67
  7. (Z, +, 0) Adelbert Chang (@adelbertchang) Simplicity in composition Scala

    World 2017 3 / 67
  8. ([a], + +, []) Adelbert Chang (@adelbertchang) Simplicity in composition

    Scala World 2017 4 / 67
  9. (A → A, ◦, a → a) Adelbert Chang (@adelbertchang)

    Simplicity in composition Scala World 2017 5 / 67
  10. trait Monoid[A] { def combine(x: A, y: A): A def

    empty: A } Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 6 / 67
  11. 1 2 3 4 5 6 7 8 Adelbert Chang

    (@adelbertchang) Simplicity in composition Scala World 2017 7 / 67
  12. 3 3 4 5 6 7 8 Adelbert Chang (@adelbertchang)

    Simplicity in composition Scala World 2017 8 / 67
  13. 6 4 5 6 7 8 Adelbert Chang (@adelbertchang) Simplicity

    in composition Scala World 2017 9 / 67
  14. 15 6 7 8 Adelbert Chang (@adelbertchang) Simplicity in composition

    Scala World 2017 10 / 67
  15. 36 Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017

    11 / 67
  16. 1 2 3 4 5 6 7 8 Adelbert Chang

    (@adelbertchang) Simplicity in composition Scala World 2017 12 / 67
  17. 3 7 11 15 Adelbert Chang (@adelbertchang) Simplicity in composition

    Scala World 2017 13 / 67
  18. 10 26 Adelbert Chang (@adelbertchang) Simplicity in composition Scala World

    2017 14 / 67
  19. 36 Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017

    15 / 67
  20. 1 2 3 4 5 6 7 8 3 7

    11 15 10 26 36 Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 16 / 67
  21. Associative composition allows for modular decomposition and reasoning. Adelbert Chang

    (@adelbertchang) Simplicity in composition Scala World 2017 17 / 67
  22. Composing programs A Adelbert Chang (@adelbertchang) Simplicity in composition Scala

    World 2017 18 / 67
  23. Composing programs F[A] Adelbert Chang (@adelbertchang) Simplicity in composition Scala

    World 2017 19 / 67
  24. Composing programs (F[A], F[A]) => F[A] Adelbert Chang (@adelbertchang) Simplicity

    in composition Scala World 2017 20 / 67
  25. Composing programs (F[A], F[B]) => F[?] Adelbert Chang (@adelbertchang) Simplicity

    in composition Scala World 2017 21 / 67
  26. Composing programs (F[A], F[B]) => F[(A, B)] Adelbert Chang (@adelbertchang)

    Simplicity in composition Scala World 2017 22 / 67
  27. Composing programs F( ): type of program Adelbert Chang (@adelbertchang)

    Simplicity in composition Scala World 2017 23 / 67
  28. Composing programs F( ): type of program ⊗ : F(A)

    × F(B) → F((A, B)) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 23 / 67
  29. Composing programs F( ): type of program ⊗ : F(A)

    × F(B) → F((A, B)) η : A → F(A) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 23 / 67
  30. Composing programs F( ): type of program ⊗ : F(A)

    × F(B) → F((A, B)) η : A → F(A) (fa ⊗ fb) ⊗ fc ∼ = fa ⊗ (fb ⊗ fc) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 23 / 67
  31. Composing programs F( ): type of program ⊗ : F(A)

    × F(B) → F((A, B)) η : A → F(A) (fa ⊗ fb) ⊗ fc ∼ = fa ⊗ (fb ⊗ fc) fa ∼ = fa ⊗ ηUnit ∼ = ηUnit ⊗ fa Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 23 / 67
  32. Composing programs def zipOption[A, B] (oa: Option[A], ob: Option[B]): Option[(A,

    B)] = (oa, ob) match { case (Some(a), Some(b)) => Some((a, b)) case _ => None } Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 24 / 67
  33. Composing programs def zipOption[A, B] (oa: Option[A], ob: Option[B]): Option[(A,

    B)] = (oa, ob) match { case (Some(a), Some(b)) => Some((a, b)) case _ => None } def pureOption[A](a: A): Option[A] = Some(a) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 24 / 67
  34. Composing programs def zipList[A, B] (la: List[A], lb: List[B]): List[(A,

    B)] = la match { case Nil => Nil case h :: t => lb.map((h, _)) ++ zipList(t, lb) } Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 25 / 67
  35. Composing programs def zipList[A, B] (la: List[A], lb: List[B]): List[(A,

    B)] = la match { case Nil => Nil case h :: t => lb.map((h, _)) ++ zipList(t, lb) } def pureList[A](a: A): List[A] = List(a) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 25 / 67
  36. Composing programs def zipFunction[A, B, X] (f: X => A,

    g: X => B): X => (A, B) = (x: X) => (f(x), g(x)) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 26 / 67
  37. Composing programs def zipFunction[A, B, X] (f: X => A,

    g: X => B): X => (A, B) = (x: X) => (f(x), g(x)) def pureFunction[A, X](a: A): X => A = (_: X) => a Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 26 / 67
  38. /** Same as Applicative */ trait Monoidal[F[_]] { def zip[A,

    B](fa: F[A], fb: F[B]): F[(A, B)] def pure[A](a: A): F[A] /* def map[A, B](fa: F[A])(f: A => B): F[B] */ } Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 27 / 67
  39. User input Password reqs Features Latest posts Sign-up form Featured

    Welcome page Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 28 / 67
  40. Composing programs (F[A], F[B]) => F[(A, B)] Adelbert Chang (@adelbertchang)

    Simplicity in composition Scala World 2017 29 / 67
  41. Composing independent programs (F[A], F[B]) => F[(A, B)] Adelbert Chang

    (@adelbertchang) Simplicity in composition Scala World 2017 30 / 67
  42. Composing programs F[A] Adelbert Chang (@adelbertchang) Simplicity in composition Scala

    World 2017 31 / 67
  43. Composing dependent programs (F[A], A => F[B]) => F[B] Adelbert

    Chang (@adelbertchang) Simplicity in composition Scala World 2017 32 / 67
  44. Composing dependent programs F( ): type of program 1> =

    >: (A → F(B) × B → F(C)) → A → F(C) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 33 / 67
  45. Composing dependent programs F( ): type of program > >=:

    (F(A) × A → F(B)) → F(B) 1> = >: (A → F(B) × B → F(C)) → A → F(C) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 33 / 67
  46. Composing dependent programs F( ): type of program > >=:

    (F(A) × A → F(B)) → F(B) η : A → F(A) 1> = >: (A → F(B) × B → F(C)) → A → F(C) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 33 / 67
  47. Composing dependent programs F( ): type of program > >=:

    (F(A) × A → F(B)) → F(B) η : A → F(A) (fa > >= f ) > >= g = fa > >= (f >=> g)1 1> = >: (A → F(B) × B → F(C)) → A → F(C) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 33 / 67
  48. Composing dependent programs F( ): type of program > >=:

    (F(A) × A → F(B)) → F(B) η : A → F(A) (fa > >= f ) > >= g = fa > >= (f >=> g)1 f (x) = η(x) > >= f 1> = >: (A → F(B) × B → F(C)) → A → F(C) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 33 / 67
  49. Composing dependent programs F( ): type of program > >=:

    (F(A) × A → F(B)) → F(B) η : A → F(A) (fa > >= f ) > >= g = fa > >= (f >=> g)1 f (x) = η(x) > >= f fa = fa > >= η 1> = >: (A → F(B) × B → F(C)) → A → F(C) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 33 / 67
  50. Composing dependent programs def flatMapOption[A, B] (oa: Option[A], f: A

    => Option[B]): Option[B] = oa match { case Some(a) => f(a) case None => None } Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 34 / 67
  51. Composing dependent programs def flatMapList[A, B] (la: List[A], f: A

    => List[B]): List[B] = la match { case Nil => Nil case h :: t => f(h) ++ flatMapList(t, f) } Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 35 / 67
  52. Composing dependent programs def flatMapFunction[A, B, X] (fa: X =>

    A, f: A => (X => B)): X => B = (x: X) => f(fa(x))(x) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 36 / 67
  53. trait Monad[F[_]] { def flatMap[A, B](fa: F[A])(f: A => F[B]):

    F[B] def pure[A](a: A): F[A] } Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 37 / 67
  54. trait Monad[F[_]] extends Monoidal[F] { def flatMap[A, B](fa: F[A])(f: A

    => F[B]): F[B] def pure[A](a: A): F[A] } Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 38 / 67
  55. A nicer monad (fa > >= f ) > >=

    g = fa > >= (f >=> g) f (x) = η(x) > >= f fa = fa > >= η Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 39 / 67
  56. A nicer monad f : A → F(B) g :

    B → F(C) h : C → F(D) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 40 / 67
  57. A nicer monad f : A → F(B) g :

    B → F(C) h : C → F(D) (f >=> g) >=> h = f >=> (g >=> h) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 40 / 67
  58. A nicer monad f : A → F(B) g :

    B → F(C) h : C → F(D) (f >=> g) >=> h = f >=> (g >=> h) f = f >=> η = η >=> f Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 40 / 67
  59. User info Friends Cookies Logs Profile Recommendations News feed Adelbert

    Chang (@adelbertchang) Simplicity in composition Scala World 2017 41 / 67
  60. Category theory studies the algebra of composition. Adelbert Chang (@adelbertchang)

    Simplicity in composition Scala World 2017 42 / 67
  61. Category theory objects: A, B, C ... Adelbert Chang (@adelbertchang)

    Simplicity in composition Scala World 2017 43 / 67
  62. Category theory objects: A, B, C ... arrows: f :

    A → B, g : B → C ... Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 43 / 67
  63. Category theory objects: A, B, C ... arrows: f :

    A → B, g : B → C ... 1A : A → A Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 43 / 67
  64. Category theory objects: A, B, C ... arrows: f :

    A → B, g : B → C ... 1A : A → A (f ◦ g) ◦ h = f ◦ (g ◦ h) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 43 / 67
  65. Category theory objects: A, B, C ... arrows: f :

    A → B, g : B → C ... 1A : A → A (f ◦ g) ◦ h = f ◦ (g ◦ h) f = f ◦ 1A = 1A ◦ f Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 43 / 67
  66. Category theory B A C g 1B f g◦f 1A

    1C Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 44 / 67
  67. Category theory B A C g 1B f g◦f 1A

    1C Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 44 / 67
  68. Category theory B A C g 1B f g◦f 1A

    1C Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 44 / 67
  69. Category theory: monoids • x y x⊕y 1A Adelbert Chang

    (@adelbertchang) Simplicity in composition Scala World 2017 45 / 67
  70. Category theory: monoids • x y x⊕y 1A Adelbert Chang

    (@adelbertchang) Simplicity in composition Scala World 2017 45 / 67
  71. Category theory: monoids • x y x⊕y 1A Adelbert Chang

    (@adelbertchang) Simplicity in composition Scala World 2017 45 / 67
  72. Category theory: monoids • x y x⊕y 1A Adelbert Chang

    (@adelbertchang) Simplicity in composition Scala World 2017 45 / 67
  73. Category theory: monads Adelbert Chang (@adelbertchang) Simplicity in composition Scala

    World 2017 46 / 67
  74. Category theory: monads F(B) A F(C) f ?◦f Adelbert Chang

    (@adelbertchang) Simplicity in composition Scala World 2017 46 / 67
  75. Category theory: monads F(B) A F(C) f ?◦f > >=:

    (F(B) × B → F(C)) → F(C) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 46 / 67
  76. Category theory: monads F(B) A F(C) f ?◦f > >=:

    (B → F(C)) → F(B) → F(C) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 47 / 67
  77. Category theory: monads F(B) A F(C) g∗ f g∗◦f >

    >=: (B → F(C)) → F(B) → F(C) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 48 / 67
  78. Category theory: monads B A C g 1B B→F(B) f

    g ◦f 1A A→F(A) 1C C→F(C) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 49 / 67
  79. Category theory: monads B A C g 1B B→F(B) f

    g ◦f 1A A→F(A) 1C C→F(C) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 49 / 67
  80. Category theory: monads B A C g 1B B→F(B) f

    g ◦f 1A A→F(A) 1C C→F(C) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 49 / 67
  81. Category theory: monads B A C g 1B B→F(B) f

    g ◦f 1A A→F(A) 1C C→F(C) η : X → F(X) Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 49 / 67
  82. User info Friends Cookies Logs Profile Recommendations News feed Adelbert

    Chang (@adelbertchang) Simplicity in composition Scala World 2017 50 / 67
  83. What if we have different monoids, monads, etc? Adelbert Chang

    (@adelbertchang) Simplicity in composition Scala World 2017 51 / 67
  84. (Monoid[A], Monoid[B]) => Monoid[?] Adelbert Chang (@adelbertchang) Simplicity in composition

    Scala World 2017 52 / 67
  85. Product composition: monoids (Monoid[A], Monoid[B]) => Monoid[(A, B)] Adelbert Chang

    (@adelbertchang) Simplicity in composition Scala World 2017 53 / 67
  86. Product composition: monoids def combine(x: (A, B), y: (A, B)):

    (A, B) = { val a = x._1 combine y._1 val b = x._2 combine y._2 (a, b) } 0Assuming Monoid[A] and Monoid[B] Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 54 / 67
  87. Product composition: monoids def combine(x: (A, B), y: (A, B)):

    (A, B) = { val a = x._1 combine y._1 val b = x._2 combine y._2 (a, b) } def empty: (A, B) = (empty[A], empty[B]) 0Assuming Monoid[A] and Monoid[B] Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 54 / 67
  88. (Monoidal[F], Monoidal[G]) => Monoidal[?] Adelbert Chang (@adelbertchang) Simplicity in composition

    Scala World 2017 55 / 67
  89. Product composition: lax monoidal functors type L[X] = (F[X], G[X])

    (Monoidal[F], Monoidal[G]) => Monoidal[L] Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 56 / 67
  90. Product composition: lax monoidal functors def zip[A, B](x: (F[A], G[A]),

    y: (F[B], G[B])): (F[(A, B)], G[(A, B)]) = { val f = x._1 zip y._1 val g = x._2 zip y._2 (f, g) } 0Assuming Monoidal[F] and Monoidal[G] Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 57 / 67
  91. Product composition: lax monoidal functors def zip[A, B](x: (F[A], G[A]),

    y: (F[B], G[B])): (F[(A, B)], G[(A, B)]) = { val f = x._1 zip y._1 val g = x._2 zip y._2 (f, g) } def pure[A](a: A): (F[A], G[A]) = (a.pure[F], a.pure[G]) 0Assuming Monoidal[F] and Monoidal[G] Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 57 / 67
  92. Product composition: monads type L[X] = (F[X], G[X]) (Monad[F], Monad[G])

    => Monad[L] Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 58 / 67
  93. Product composition: monads def flatMap[A, B] (xa: (F[A], G[A]))(ff: A

    => (F[B], G[B])): (F[(A, B)], G[(A, B)]) = { val f = xa._1.flatMap(a => ff(a)._1) val g = xa._2.flatMap(a => ff(a)._2) (f, g) } 0Assuming Monad[F] and Monad[G] Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 59 / 67
  94. Nested composition: lax monoidal functors type L[X] = F[G[X]] (Monoidal[F],

    Monoidal[G]) => Monoidal[L] Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 60 / 67
  95. User input Password reqs Features Latest posts Sign-up form Featured

    Welcome page Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 61 / 67
  96. Nested composition: lax monoidal functors def zip[A, B](fga: F[G[A]], fgb:

    F[G[B]]): F[G[(A, B)]] = { val fp: F[(G[A], G[B])] = fga zip fgb fp.map { case (ga, gb) => ga zip gb } } 0Assuming Monoidal[F] and Monoidal[G] Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 62 / 67
  97. Nested composition: lax monoidal functors def zip[A, B](fga: F[G[A]], fgb:

    F[G[B]]): F[G[(A, B)]] = { val fp: F[(G[A], G[B])] = fga zip fgb fp.map { case (ga, gb) => ga zip gb } } def pure[A](a: A): F[G[A]] = a.pure[G].pure[F] 0Assuming Monoidal[F] and Monoidal[G] Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 62 / 67
  98. Nested composition: monads type L[X] = F[G[X]] (Monad[F], Monad[G]) =>

    Monad[L] Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 63 / 67
  99. Nested composition: monads type L[X] = F[G[X]] (Monad[F], Monad[G]) =>

    Monad[L] Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 64 / 67
  100. Nested composition: monads def flatMap[A, B](fga: F[G[A]](f: A => F[G[B]]):

    F[G[B]] = 0Assuming Monad[F] and Monad[G] Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 65 / 67
  101. Nested composition: monads def flatMap[A, B](fga: F[G[A]](f: A => F[G[B]]):

    F[G[B]] = fga.flatMap { (ga: G[A]) => ??? } 0Assuming Monad[F] and Monad[G] Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 65 / 67
  102. Review Associative composition allows for modular decomposition and reasoning Adelbert

    Chang (@adelbertchang) Simplicity in composition Scala World 2017 66 / 67
  103. Review Associative composition allows for modular decomposition and reasoning Monoids

    compose A’s, lax monoidal/applicative functors compose independent programs, monads compose dependent programs Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 66 / 67
  104. Review Associative composition allows for modular decomposition and reasoning Monoids

    compose A’s, lax monoidal/applicative functors compose independent programs, monads compose dependent programs Category theory studies composition, and each of the above can be framed as a category Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 66 / 67
  105. Review Associative composition allows for modular decomposition and reasoning Monoids

    compose A’s, lax monoidal/applicative functors compose independent programs, monads compose dependent programs Category theory studies composition, and each of the above can be framed as a category Monoids compose Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 66 / 67
  106. Review Associative composition allows for modular decomposition and reasoning Monoids

    compose A’s, lax monoidal/applicative functors compose independent programs, monads compose dependent programs Category theory studies composition, and each of the above can be framed as a category Monoids compose Lax monoidal/applicative functors compose Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 66 / 67
  107. Review Associative composition allows for modular decomposition and reasoning Monoids

    compose A’s, lax monoidal/applicative functors compose independent programs, monads compose dependent programs Category theory studies composition, and each of the above can be framed as a category Monoids compose Lax monoidal/applicative functors compose Monads in general do not compose See: monad transformers, extensible (algebraic) effects Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 66 / 67
  108. References Equational reasoning at scale - Gabriel Gonzalez http://www.haskellforall.com/2014/07/ equational-reasoning-at-scale.html

    Invariant Shadows - Michael Pilquist http://mpilquist.github.io/blog/2015/06/22/ invariant-shadows-part-2/ All About Applicative - Me! https://www.youtube.com/watch?v=Mn7BtPALFys A categorial view of computational effects - Emily Riehl https://www.youtube.com/watch?v=6t6bsWVOIzs Conceptual Mathematics - F. William Lawvere and Stephen H. Schanuel Adelbert Chang (@adelbertchang) Simplicity in composition Scala World 2017 67 / 67