Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Why I Like Functional Programming

Why I Like Functional Programming

Shortly after Adelbert Chang entered college as a computer science major, he contemplated changing his major several times, usually in the direction of physics and mathematics. That all changed when he was introduced to functional programming — at once both mysterious and beautiful. In this talk, Adelbert will elaborate on his early perspectives on computer science, math, and physics, and discuss how he ended up so enamored with functional programming.

Adelbert Chang

May 22, 2015
Tweet

More Decks by Adelbert Chang

Other Decks in Programming

Transcript

  1. Why I Like
    Functional Programming
    Adelbert Chang
    Machine Learning @ Box, Inc.

    View Slide

  2. Let’s go back..
    http://gauss.cs.ucsb.edu/home/images/UCSB-from-air.jpg

    View Slide

  3. 2011

    View Slide

  4. 2011
    void insert(Node* &tree, int value) {
    if (!tree) return;
    Node *trav = tree, *parent;
    while (trav) {
    parent = trav;
    if (value < trav->data) trav = trav->left;
    else if (value > trav->data) trav = trav->right;
    else break;
    }
    if (value < parent->data)
    parent->left = new Node(value);
    else
    parent->right = new Node(value);
    }

    View Slide

  5. Physics and Math

    View Slide

  6. Physics and Math
    •Simplicity and consistency across problems

    View Slide

  7. Physics and Math
    •Simplicity and consistency across problems
    •Example: Deriving laws of motion from first principles

    View Slide

  8. Physics and Math
    •Simplicity and consistency across problems
    •Example: Deriving laws of motion from first principles
    •vf = v0 + a Δt

    View Slide

  9. Physics and Math
    •Simplicity and consistency across problems
    •Example: Deriving laws of motion from first principles
    •vf = v0 + a Δt
    •vavg = v0 + ½aΔt

    View Slide

  10. Physics and Math
    •Simplicity and consistency across problems
    •Example: Deriving laws of motion from first principles
    •vf = v0 + a Δt
    •vavg = v0 + ½aΔt
    •x = x0 + v0t + ½at2

    View Slide

  11. Deriving x = x0 + v0t + ½at2
    Physics and Math

    View Slide

  12. Deriving x = x0 + v0t + ½at2
    vavg = Δx/Δt
    Physics and Math

    View Slide

  13. Deriving x = x0 + v0t + ½at2
    vavg = Δx/Δt
    Δx = vavg * Δt
    Physics and Math

    View Slide

  14. Deriving x = x0 + v0t + ½at2
    vavg = Δx/Δt
    Δx = vavg * Δt
    (x - x0) = vavg * Δt
    Physics and Math

    View Slide

  15. Deriving x = x0 + v0t + ½at2
    vavg = Δx/Δt
    Δx = vavg * Δt
    (x - x0) = vavg * Δt
    x = x0 + (vavg * Δt)
    Physics and Math

    View Slide

  16. Deriving x = x0 + v0t + ½at2
    vavg = Δx/Δt
    Δx = vavg * Δt
    (x - x0) = vavg * Δt
    x = x0 + (vavg * Δt)
    vavg = ½(vf + v0)
    Physics and Math

    View Slide

  17. Deriving x = x0 + v0t + ½at2
    vavg = Δx/Δt
    Δx = vavg * Δt
    (x - x0) = vavg * Δt
    x = x0 + (vavg * Δt)
    vavg = ½(vf + v0)
    a = Δv / Δt
    Physics and Math

    View Slide

  18. Deriving x = x0 + v0t + ½at2
    vavg = Δx/Δt
    Δx = vavg * Δt
    (x - x0) = vavg * Δt
    x = x0 + (vavg * Δt)
    vavg = ½(vf + v0)
    a = Δv / Δt
    a = (vf - v0) / Δt
    Physics and Math

    View Slide

  19. Deriving x = x0 + v0t + ½at2
    vavg = Δx/Δt
    Δx = vavg * Δt
    (x - x0) = vavg * Δt
    x = x0 + (vavg * Δt)
    vavg = ½(vf + v0)
    a = Δv / Δt
    a = (vf - v0) / Δt
    vf - v0 = a Δt
    Physics and Math

    View Slide

  20. Deriving x = x0 + v0t + ½at2
    vavg = Δx/Δt
    Δx = vavg * Δt
    (x - x0) = vavg * Δt
    x = x0 + (vavg * Δt)
    vavg = ½(vf + v0)
    a = Δv / Δt
    a = (vf - v0) / Δt
    vf - v0 = a Δt
    vf = v0 + a Δt
    Physics and Math

    View Slide

  21. Deriving x = x0 + v0t + ½at2
    vavg = Δx/Δt
    Δx = vavg * Δt
    (x - x0) = vavg * Δt
    x = x0 + (vavg * Δt)
    ½(v0 + aΔt + v0)
    vavg = ½(vf + v0)
    a = Δv / Δt
    a = (vf - v0) / Δt
    vf - v0 = a Δt
    vf = v0 + a Δt
    Physics and Math

    View Slide

  22. Deriving x = x0 + v0t + ½at2
    vavg = Δx/Δt
    Δx = vavg * Δt
    (x - x0) = vavg * Δt
    x = x0 + (vavg * Δt)
    ½(v0 + aΔt + v0)
    ½(2v0 + a Δt)
    vavg = ½(vf + v0)
    a = Δv / Δt
    a = (vf - v0) / Δt
    vf - v0 = a Δt
    vf = v0 + a Δt
    Physics and Math

    View Slide

  23. Deriving x = x0 + v0t + ½at2
    vavg = Δx/Δt
    Δx = vavg * Δt
    (x - x0) = vavg * Δt
    x = x0 + (vavg * Δt)
    ½(v0 + aΔt + v0)
    ½(2v0 + a Δt)
    vavg = v0 + ½aΔt
    vavg = ½(vf + v0)
    a = Δv / Δt
    a = (vf - v0) / Δt
    vf - v0 = a Δt
    vf = v0 + a Δt
    Physics and Math

    View Slide

  24. Deriving x = x0 + v0t + ½at2
    vavg = Δx/Δt
    Δx = vavg * Δt
    (x - x0) = vavg * Δt
    x = x0 + (vavg * Δt)
    x = x0 + ((v0 + ½aΔt) * Δt)
    ½(v0 + aΔt + v0)
    ½(2v0 + a Δt)
    vavg = v0 + ½aΔt
    vavg = ½(vf + v0)
    a = Δv / Δt
    a = (vf - v0) / Δt
    vf - v0 = a Δt
    vf = v0 + a Δt
    Physics and Math

    View Slide

  25. Deriving x = x0 + v0t + ½at2
    vavg = Δx/Δt
    Δx = vavg * Δt
    (x - x0) = vavg * Δt
    x = x0 + (vavg * Δt)
    x = x0 + ((v0 + ½aΔt) * Δt)
    x0 + v0t + ½at2
    ½(v0 + aΔt + v0)
    ½(2v0 + a Δt)
    vavg = v0 + ½aΔt
    vavg = ½(vf + v0)
    a = Δv / Δt
    a = (vf - v0) / Δt
    vf - v0 = a Δt
    vf = v0 + a Δt
    Physics and Math

    View Slide

  26. 2012

    View Slide

  27. 2012
    sealed abstract class Tree
    case class Branch(data: Int, left: Tree, right: Tree)
    extends Tree
    case class Leaf() extends Tree
    def insert(tree: Tree, value: Int): Tree =
    tree match {
    case Leaf() => Branch(value, Leaf(), Leaf())
    case [email protected](d, l, r) =>
    if (value < d) Branch(d, insert(l, value), r)
    else if (value > d) Branch(d, l, insert(r, value)
    else b
    }

    View Slide

  28. Hmm.. functional programming seems pretty cool.

    View Slide

  29. But is it as cool as physics and math?
    Hmm.. functional programming seems pretty cool.

    View Slide

  30. Functional
    Programming

    View Slide

  31. Functional
    Programming
    programming with functions

    View Slide

  32. programming with pure functions
    Functional
    Programming

    View Slide

  33. programming with pure functions
    Functional
    Programming

    View Slide

  34. Functions

    View Slide

  35. def parseIntPartial(s: String): Int =
    s.toInt // can throw NumberFormatException
    Functions

    View Slide

  36. def parseIntPartial(s: String): Int =
    s.toInt // can throw NumberFormatException
    Functions
    def parseIntTotal(s: String): Option[Int] =
    try {
    Some(s.toInt)
    } catch {
    case nfe: NumberFormatException => None
    }

    View Slide

  37. Functions

    View Slide

  38. class Rng(var seed: Long) {
    def nextInt(): Int = {
    val int = getInt(seed)
    mutate(seed)
    int
    }
    }
    Functions

    View Slide

  39. class Rng(var seed: Long) {
    def nextInt(): Int = {
    val int = getInt(seed)
    mutate(seed)
    int
    }
    }
    case class Rng(seed: Long) {
    def nextInt: (Rng, Int) = {
    val int = getInt(seed)
    val newSeed = f(seed)
    (Rng(newSeed), int)
    }
    }
    Functions

    View Slide

  40. Referential Transparency
    * Taken from Higher Order blog post "What Purity Is and Isn't" May 29, 2015 http://blog.higher-order.com/blog/2012/09/13/what-purity-is-and-isnt/

    View Slide

  41. Referential Transparency
    An expression e is referentially transparent if
    * Taken from Higher Order blog post "What Purity Is and Isn't" May 29, 2015 http://blog.higher-order.com/blog/2012/09/13/what-purity-is-and-isnt/

    View Slide

  42. Referential Transparency
    An expression e is referentially transparent if
    for all programs p
    * Taken from Higher Order blog post "What Purity Is and Isn't" May 29, 2015 http://blog.higher-order.com/blog/2012/09/13/what-purity-is-and-isnt/

    View Slide

  43. Referential Transparency
    An expression e is referentially transparent if
    for all programs p
    every occurrence of e in p
    * Taken from Higher Order blog post "What Purity Is and Isn't" May 29, 2015 http://blog.higher-order.com/blog/2012/09/13/what-purity-is-and-isnt/

    View Slide

  44. Referential Transparency
    An expression e is referentially transparent if
    for all programs p
    every occurrence of e in p
    can be replaced with the result of evaluating e
    * Taken from Higher Order blog post "What Purity Is and Isn't" May 29, 2015 http://blog.higher-order.com/blog/2012/09/13/what-purity-is-and-isnt/

    View Slide

  45. Referential Transparency
    An expression e is referentially transparent if
    for all programs p
    every occurrence of e in p
    can be replaced with the result of evaluating e
    without changing the result of evaluating p.*
    * Taken from Higher Order blog post "What Purity Is and Isn't" May 29, 2015 http://blog.higher-order.com/blog/2012/09/13/what-purity-is-and-isnt/

    View Slide

  46. Referential Transparency

    View Slide

  47. x4 - 12x2 + 36 = 0
    Referential Transparency

    View Slide

  48. x4 - 12x2 + 36 = 0
    y = x2
    Referential Transparency

    View Slide

  49. x4 - 12x2 + 36 = 0
    y = x2
    y2 - 12y + 36 = 0
    Referential Transparency

    View Slide

  50. x4 - 12x2 + 36 = 0
    y = x2
    y2 - 12y + 36 = 0
    ax2 + bx + c = 0
    Referential Transparency

    View Slide

  51. x4 - 12x2 + 36 = 0
    y = x2
    y2 - 12y + 36 = 0
    ax2 + bx + c = 0
    (-b ± √ b2 - 4ac) / 2a
    Referential Transparency

    View Slide

  52. x4 - 12x2 + 36 = 0
    y = x2
    y2 - 12y + 36 = 0
    ax2 + bx + c = 0
    (-b ± √ b2 - 4ac) / 2a
    a = 1 b = -12 c = 36
    Referential Transparency

    View Slide

  53. x4 - 12x2 + 36 = 0
    y = x2
    y2 - 12y + 36 = 0
    ax2 + bx + c = 0
    (-b ± √ b2 - 4ac) / 2a
    a = 1 b = -12 c = 36
    (-(-12) ± √ (-12)2 - 4(1)(36)) / 2(1)
    Referential Transparency

    View Slide

  54. x4 - 12x2 + 36 = 0
    y = x2
    y2 - 12y + 36 = 0
    ax2 + bx + c = 0
    (-b ± √ b2 - 4ac) / 2a
    a = 1 b = -12 c = 36
    (-(-12) ± √ (-12)2 - 4(1)(36)) / 2(1)
    12 / 2
    Referential Transparency

    View Slide

  55. x4 - 12x2 + 36 = 0
    y = x2
    y2 - 12y + 36 = 0
    ax2 + bx + c = 0
    (-b ± √ b2 - 4ac) / 2a
    a = 1 b = -12 c = 36
    (-(-12) ± √ (-12)2 - 4(1)(36)) / 2(1)
    12 / 2
    y = 6
    Referential Transparency

    View Slide

  56. x4 - 12x2 + 36 = 0
    y = x2
    y2 - 12y + 36 = 0
    ax2 + bx + c = 0
    (-b ± √ b2 - 4ac) / 2a
    a = 1 b = -12 c = 36
    (-(-12) ± √ (-12)2 - 4(1)(36)) / 2(1)
    12 / 2
    y = 6
    x2 = 6
    Referential Transparency

    View Slide

  57. x4 - 12x2 + 36 = 0
    y = x2
    y2 - 12y + 36 = 0
    ax2 + bx + c = 0
    (-b ± √ b2 - 4ac) / 2a
    a = 1 b = -12 c = 36
    (-(-12) ± √ (-12)2 - 4(1)(36)) / 2(1)
    12 / 2
    y = 6
    x2 = 6
    x = ± √ 6
    Referential Transparency

    View Slide

  58. Referential Transparency

    View Slide

  59. def userInfo(id: UserId): Future[UserData]
    val userId = . . .
    val fetchData = userInfo(userId)
    fetchData.retry {
    case StatusCode(429) => fetchData
    }
    Referential Transparency

    View Slide

  60. def userInfo(id: UserId): Future[UserData]
    val userId = . . .
    val fetchData = userInfo(userId)
    fetchData.retry {
    case StatusCode(429) => fetchData
    }
    Referential Transparency

    View Slide

  61. def userInfo(id: UserId): Future[UserData]
    val userId = . . .
    val fetchData = userInfo(userId)
    fetchData.retry {
    case StatusCode(429) => userInfo(userId)
    }
    Referential Transparency

    View Slide

  62. def userInfo(id: UserId): Future[UserData]
    val userId = . . .
    val fetchData = userInfo(userId)
    fetchData.retry {
    case StatusCode(429) => userInfo(userId)
    }
    ???
    Referential Transparency

    View Slide

  63. def userInfo(id: UserId): Task[UserData]
    val userId = . . .
    val fetchData = userInfo(userId)
    fetchData.retry {
    case StatusCode(429) => fetchData
    }
    Referential Transparency

    View Slide

  64. trait Task[A] {
    def unsafeRun(): A
    }
    def userInfo(id: UserId): Task[UserData]
    val userId = . . .
    val fetchData = userInfo(userId)
    fetchData.retry {
    case StatusCode(429) => fetchData
    }
    Referential Transparency

    View Slide

  65. Functions

    View Slide

  66. bar: B => C baz: C => D
    foo: A => B
    Functions

    View Slide

  67. baz.compose(bar).compose(foo): A => D
    bar: B => C baz: C => D
    foo: A => B
    Functions

    View Slide

  68. Tracking Effects

    View Slide

  69. Tracking Effects
    •Interesting programs will have effects
    •Optional values, error handling, asynchronous
    computation, input/output
    •Usual means aren’t quite nice

    View Slide

  70. Tracking Effects
    •Interesting programs will have effects
    •Optional values, error handling, asynchronous
    computation, input/output
    •Usual means aren’t quite nice
    Solution:

    View Slide

  71. Tracking Effects
    •Interesting programs will have effects
    •Optional values, error handling, asynchronous
    computation, input/output
    •Usual means aren’t quite nice
    Solution:
    Reify effects as values.

    View Slide

  72. Missing values

    View Slide

  73. // A value that might exist is either..
    sealed abstract class Option[A]
    // ..there
    final case class Some[A](a: A) extends Option[A]
    // .. or not there
    final case class None[A]() extends Option[A]
    Missing values

    View Slide

  74. def lookup(map: Map[Foo, Bar], foo: Foo): Option[Bar] =
    if (map.contains(foo)) Some(map(foo))
    else None
    Missing values

    View Slide

  75. Errors
    sealed abstract class Either[+E, +A]
    final case class Success[+A](a: A) extends Either[Nothing, A]
    final case class Failure[+E](e: E) extends Either[E, Nothing]

    View Slide

  76. sealed abstract class Error
    final case object UserDoesNotExist extends Error
    final case object InvalidToken extends Error
    def userInfo(uid: UserId,
    tk: Token): Either[Error, UserInfo] = . . .
    Errors

    View Slide

  77. Manipulating Effects

    View Slide

  78. Manipulating Effects
    •The type signature of our functions reflect the
    effects involved

    View Slide

  79. Manipulating Effects
    •The type signature of our functions reflect the
    effects involved
    def tokenFor(uid: UserId): Option[EncryptedToken]
    def decrypt(token: EncryptedToken): Token
    /** Client side */
    val encrypted: Option[EncryptedToken] =
    tokenFor(. . .)
    // Want EncryptedToken, have Option[EncryptedToken]
    val decrypted = decrypt(???)

    View Slide

  80. /** Apply a pure function to an effectful value */
    trait Functor[F[_]] {
    def map[A, B](fa: F[A])(f: A => B): F[B]
    }
    Manipulating Effects

    View Slide

  81. /** Apply a pure function to an effectful value */
    trait Functor[F[_]] {
    def map[A, B](fa: F[A])(f: A => B): F[B]
    }
    Manipulating Effects
    new Functor[Option] {
    def map[A, B](fa: Option[A])(f: A => B): Option[B] =
    fa match {
    case Some(a) => Some(f(a))
    case None() => None()
    }
    }

    View Slide

  82. def tokenFor(uid: UserId): Option[EncryptedToken]
    def decrypt(token: EncryptedToken): Token
    /** Client side */
    val encrypted: Option[EncryptedToken] =
    tokenFor(. . .)
    val decrypted = encrypted.map(tk => decrypt(tk))
    Manipulating Effects

    View Slide

  83. •Similar mechanisms for manipulating multiple
    effects
    def tokenFor(uid: UserId): Option[EncryptedToken]
    def decrypt(token: EncryptedToken): Token
    /** Client side */
    val encrypted: Option[EncryptedToken] =
    tokenFor(. . .)
    val decrypted = encrypted.map(tk => decrypt(tk))
    Manipulating Effects

    View Slide

  84. Lens

    View Slide

  85. Lens
    •Often want getters/setters when working with data

    View Slide

  86. Lens
    •Often want getters/setters when working with data
    •If getters/setters are per-object, cannot compose

    View Slide

  87. Lens
    •Often want getters/setters when working with data
    •If getters/setters are per-object, cannot compose
    •As with effects, reify as data
    •Getter: get an A field in an object S
    •Setter: change an A field in an object S

    View Slide

  88. Lens
    •Often want getters/setters when working with data
    •If getters/setters are per-object, cannot compose
    •As with effects, reify as data
    •Getter: get an A field in an object S
    •Setter: change an A field in an object S
    trait Lens[S, A] {
    def get(s: S): A
    def set(s: S, a: A): S
    }

    View Slide

  89. trait Lens[S, A] { outer =>
    def get(s: S): A
    def set(s: S, a: A): S
    def modify(s: S, f: A => A): S =
    set(s, f(get(s)))
    def compose[B](other: Lens[A, B]): Lens[S, B] =
    new Lens[S, B] {
    def get(s: S): B = other.get(get(s))
    def set(s: S, b: B): S =
    set(s, other.set(outer.get(s), b))
    }
    }
    Lens

    View Slide

  90. case class Employee(position: Position)
    object Employee {
    val position: Lens[Employee, Position] = . . .
    }
    case class Team(manager: Employee, . . .)
    object Team {
    val manager: Lens[Team, Employee] = . . .
    }
    Lens

    View Slide

  91. case class Employee(position: Position)
    object Employee {
    val position: Lens[Employee, Position] = . . .
    }
    case class Team(manager: Employee, . . .)
    object Team {
    val manager: Lens[Team, Employee] = . . .
    }
    /** Client side */
    val l: Lens[Team, Position] =
    Team.manager.compose(Employee.position)
    l.set(someTeam, somePosition)
    Lens

    View Slide

  92. Lens

    View Slide

  93. •Effect-ful modifications can be useful
    •Possibly failing: A => Option[A]
    •Many possible values: A => List[A]
    •Async: A => Task[A]
    Lens

    View Slide

  94. •Effect-ful modifications can be useful
    •Possibly failing: A => Option[A]
    •Many possible values: A => List[A]
    •Async: A => Task[A]
    trait Lens[S, A] {
    def modifyOption(s: S, f: A => Option[A]): Option[S]
    def modifyList(s: S, f: A => List[A]): List[S]
    def modifyTask(s: S, f: A => Task[A]): Task[S]
    }
    Lens

    View Slide

  95. trait Lens[S, A] {
    def modifyOption(s: S, f: A => Option[A]): Option[S] =
    f(get(s)).map(a => set(s, a))
    def modifyList(s: S, f: A => List[A]): List[S] =
    f(get(s)).map(a => set(s, a))
    def modifyTask(s: S, f: A => Task[A]): Task[S] =
    f(get(s)).map(a => set(s, a))
    }
    Lens

    View Slide

  96. trait Lens[S, A] {
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S] =
    f(get(s)).map(a => set(s, a))
    }
    Lens

    View Slide

  97. trait Lens[S, A] {
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S] =
    f(get(s)).map(a => set(s, a))
    }
    •Example functors:
    Lens

    View Slide

  98. trait Lens[S, A] {
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S] =
    f(get(s)).map(a => set(s, a))
    }
    •Example functors:
    •Option, Either, Future, List, IO
    Lens

    View Slide

  99. trait Lens[S, A] {
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S] =
    f(get(s)).map(a => set(s, a))
    }
    •Example functors:
    •Option, Either, Future, List, IO
    •What if we want to just modify without any effect?
    Lens

    View Slide

  100. trait Lens[S, A] {
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S] =
    f(get(s)).map(a => set(s, a))
    }
    •Example functors:
    •Option, Either, Future, List, IO
    •What if we want to just modify without any effect?
    •We want the F[A] to just be a plain A
    Lens

    View Slide

  101. trait Lens[S, A] {
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S] =
    f(get(s)).map(a => set(s, a))
    }
    •Example functors:
    •Option, Either, Future, List, IO
    •What if we want to just modify without any effect?
    •We want the F[A] to just be a plain A
    •Type-level identity function
    Lens

    View Slide

  102. trait Lens[S, A] {
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S] =
    f(get(s)).map(a => set(s, a))
    }
    •Example functors:
    •Option, Either, Future, List, IO
    •What if we want to just modify without any effect?
    •We want the F[A] to just be a plain A
    •Type-level identity function
    Lens
    def identity[A](a: A): A = a

    View Slide

  103. Id
    type Id[A] = A

    View Slide

  104. Id
    type Id[A] = A
    new Functor[Id] {
    def map[A, B](fa: Id[A])(f: A => B): Id[B] =
    }

    View Slide

  105. Id
    type Id[A] = A
    new Functor[Id] {
    def map[A, B](fa: Id[A])(f: A => B): Id[B] =
    }

    View Slide

  106. type Id[A] = A
    new Functor[Id] {
    def map[A, B](fa: A)(f: A => B): B =
    }
    Id

    View Slide

  107. type Id[A] = A
    new Functor[Id] {
    def map[A, B](fa: A)(f: A => B): B = f(fa)
    }
    Id

    View Slide

  108. trait Lens[S, A] {
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S] =
    f(get(s)).map(a => set(s, a))
    def modify(s: S, f: A => A): S = modifyF[Id](s, f)
    }
    Id

    View Slide

  109. Setting
    trait Lens[S, A] {
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S] =
    f(get(s)).map(a => set(s, a))
    def modify(s: S, f: A => A): S = modifyF[Id](s, f)
    def set(s: S, a: A): S = modify(s, const(a))
    }

    View Slide

  110. Setting
    trait Lens[S, A] {
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S] =
    f(get(s)).map(a => set(s, a))
    def modify(s: S, f: A => A): S = modifyF[Id](s, f)
    def set(s: S, a: A): S = modify(s, const(a))
    }
    def const[A, B](a: A)(b: B): A = a

    View Slide

  111. Setting
    trait Lens[S, A] {
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S] =
    f(get(s)).map(a => set(s, a))
    def modify(s: S, f: A => A): S = modifyF[Id](s, f)
    def set(s: S, a: A): S = modify(s, const(a))
    }
    def const[A, B](a: A)(b: B): A = a

    View Slide

  112. trait Lens[S, A] {
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S]
    def get(s: S): A
    def modify(s: S, f: A => A): S = modifyF[Id](s, f)
    def set(s: S, a: A): S = modify(s, const(a))
    }
    def const[A, B](a: A)(b: B): A = a
    Setting

    View Slide

  113. Getting
    trait Lens[S, A] {
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S]
    def get(s: S): A
    }

    View Slide

  114. Getting
    trait Lens[S, A] {
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S]
    def get(s: S): A
    }
    •Can we define `get` in terms of `modify`?

    View Slide

  115. Getting
    trait Lens[S, A] {
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S]
    def get(s: S): A
    }
    •Can we define `get` in terms of `modify`?
    •`modifyF` gives us some F[S].. but we want an A

    View Slide

  116. Getting
    trait Lens[S, A] {
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S]
    def get(s: S): A
    }
    •Can we define `get` in terms of `modify`?
    •`modifyF` gives us some F[S].. but we want an A
    •We need some way of "ignoring" the S
    parameter and still get an A back

    View Slide

  117. Getting
    trait Lens[S, A] {
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S]
    def get(s: S): A
    }
    •Can we define `get` in terms of `modify`?
    •`modifyF` gives us some F[S].. but we want an A
    •We need some way of "ignoring" the S
    parameter and still get an A back
    •Type-level constant function

    View Slide

  118. Getting
    trait Lens[S, A] {
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S]
    def get(s: S): A
    }
    •Can we define `get` in terms of `modify`?
    •`modifyF` gives us some F[S].. but we want an A
    •We need some way of "ignoring" the S
    parameter and still get an A back
    •Type-level constant function
    def const[A, B](a: A)(b: B): A = a

    View Slide

  119. Getting
    * Const[Z, ?] syntax is valid due to kind-projector plugin https://github.com/non/kind-projector

    View Slide

  120. type Const[Z, A] = Z
    Getting
    * Const[Z, ?] syntax is valid due to kind-projector plugin https://github.com/non/kind-projector

    View Slide

  121. type Const[Z, A] = Z
    new Functor[Const[Z, ?]] { // *
    def map[A, B](fa: Const[Z, A])(f: A => B): Const[Z, B]
    }
    Getting
    * Const[Z, ?] syntax is valid due to kind-projector plugin https://github.com/non/kind-projector

    View Slide

  122. type Const[Z, A] = Z
    new Functor[Const[Z, ?]] { // *
    def map[A, B](fa: Const[Z, A])(f: A => B): Const[Z, B]
    }
    Getting
    * Const[Z, ?] syntax is valid due to kind-projector plugin https://github.com/non/kind-projector

    View Slide

  123. new Functor[Const[Z, ?]] { // *
    def map[A, B](fa: Z)(f: A => B): Z =
    }
    type Const[Z, A] = Z
    Getting
    * Const[Z, ?] syntax is valid due to kind-projector plugin https://github.com/non/kind-projector

    View Slide

  124. new Functor[Const[Z, ?]] { // *
    def map[A, B](fa: Z)(f: A => B): Z = fa
    }
    type Const[Z, A] = Z
    Getting
    * Const[Z, ?] syntax is valid due to kind-projector plugin https://github.com/non/kind-projector

    View Slide

  125. trait Lens[S, Z] {
    def modifyF[F[_] : Functor](s: S, f: Z => F[Z]): F[S]
    def get(s: S): Z = {
    val const: Const[Z, S] =
    modifyF[Const[Z, ?]](s, z => z) // *
    const
    }
    }
    new Functor[Const[Z, ?]] { // *
    def map[A, B](fa: Z)(f: A => B): Z = fa
    }
    type Const[Z, A] = Z
    Getting
    * Const[Z, ?] syntax is valid due to kind-projector plugin https://github.com/non/kind-projector

    View Slide

  126. trait Lens[S, A] {
    /** Abstract */
    def modifyF[F[_] : Functor](s: S, f: A => F[A]): F[S]
    /** Implemented */
    def modify(s: S, f: A => A): S
    def get(s: S): A
    def set(s: S, a: A): S
    def compose[B](other: Lens[A, B]): Lens[S, B]
    }
    Lens

    View Slide

  127. Are Id and Const just party tricks?

    View Slide

  128. Traverse
    trait Traverse[F[_]] {
    def traverse[G[_] : Applicative, A, B]
    (fa: F[A])(f: A => G[B]): G[F[B]]
    }

    View Slide

  129. Traverse
    trait Traverse[F[_]] {
    def traverse[G[_] : Applicative, A, B]
    (fa: F[A])(f: A => G[B]): G[F[B]]
    }
    def validate[A]
    (data: List[A])(f: A => Option[B]): Option[List[B]]

    View Slide

  130. Traverse
    trait Traverse[F[_]] {
    def traverse[G[_] : Applicative, A, B]
    (fa: F[A])(f: A => G[B]): G[F[B]]
    }
    def scatterGather[A]
    (data: List[A])(f: A => Task[B]): Task[List[B]]
    def validate[A]
    (data: List[A])(f: A => Option[B]): Option[List[B]]

    View Slide

  131. Traverse
    * Const[Z, ?] syntax is valid due to kind-projector plugin https://github.com/non/kind-projector

    View Slide

  132. traverse: F[A] => (A => G[B]) => G[F[B]]
    Traverse
    * Const[Z, ?] syntax is valid due to kind-projector plugin https://github.com/non/kind-projector

    View Slide

  133. traverse: F[A] => (A => G[B]) => G[F[B]]
    traverse[Id, A, B]
    Traverse
    * Const[Z, ?] syntax is valid due to kind-projector plugin https://github.com/non/kind-projector

    View Slide

  134. traverse: F[A] => (A => G[B]) => G[F[B]]
    traverse[Id, A, B]
    F[A] => (A => Id[B]) => Id[F[B]]
    Traverse
    * Const[Z, ?] syntax is valid due to kind-projector plugin https://github.com/non/kind-projector

    View Slide

  135. traverse: F[A] => (A => G[B]) => G[F[B]]
    traverse[Id, A, B]
    F[A] => (A => Id[B]) => Id[F[B]]
    F[A] => (A => B) => F[B]
    Traverse
    * Const[Z, ?] syntax is valid due to kind-projector plugin https://github.com/non/kind-projector

    View Slide

  136. traverse: F[A] => (A => G[B]) => G[F[B]]
    traverse[Id, A, B]
    F[A] => (A => Id[B]) => Id[F[B]]
    F[A] => (A => B) => F[B]
    Traverse
    * Const[Z, ?] syntax is valid due to kind-projector plugin https://github.com/non/kind-projector

    View Slide

  137. traverse: F[A] => (A => G[B]) => G[F[B]]
    traverse[Id, A, B]
    F[A] => (A => Id[B]) => Id[F[B]]
    F[A] => (A => B) => F[B]
    traverse[Const[Z, ?], A, B] // *, If Z can be "reduced"
    Traverse
    * Const[Z, ?] syntax is valid due to kind-projector plugin https://github.com/non/kind-projector

    View Slide

  138. traverse: F[A] => (A => G[B]) => G[F[B]]
    traverse[Id, A, B]
    F[A] => (A => Id[B]) => Id[F[B]]
    F[A] => (A => B) => F[B]
    traverse[Const[Z, ?], A, B] // *, If Z can be "reduced"
    F[A] => (A => Const[Z, B]) => Const[Z, F[B]]
    Traverse
    * Const[Z, ?] syntax is valid due to kind-projector plugin https://github.com/non/kind-projector

    View Slide

  139. traverse: F[A] => (A => G[B]) => G[F[B]]
    traverse[Id, A, B]
    F[A] => (A => Id[B]) => Id[F[B]]
    F[A] => (A => B) => F[B]
    traverse[Const[Z, ?], A, B] // *, If Z can be "reduced"
    F[A] => (A => Const[Z, B]) => Const[Z, F[B]]
    F[A] => (A => Z) => Z
    Traverse
    * Const[Z, ?] syntax is valid due to kind-projector plugin https://github.com/non/kind-projector

    View Slide

  140. Interested?

    View Slide

  141. Interested?
    •Functional Programming
    •Cats, Scalaz
    •Argonaut, Atto, Monocle, Shapeless

    View Slide

  142. Interested?
    •Functional Programming
    •Cats, Scalaz
    •Argonaut, Atto, Monocle, Shapeless
    •Algebra
    •Algebird, Algebra, Breeze, Spire

    View Slide

  143. Interested?
    •Functional Programming
    •Cats, Scalaz
    •Argonaut, Atto, Monocle, Shapeless
    •Algebra
    •Algebird, Algebra, Breeze, Spire
    •Big Data
    •Scalding, Scoobi, Spark

    View Slide

  144. Interested?
    •Functional Programming
    •Cats, Scalaz
    •Argonaut, Atto, Monocle, Shapeless
    •Algebra
    •Algebird, Algebra, Breeze, Spire
    •Big Data
    •Scalding, Scoobi, Spark
    •Systems
    •Doobie, HTTP4S, Remotely, Scalaz-stream

    View Slide

  145. EOF

    View Slide