$30 off During Our Annual Pro Sale. View Details »

Functional Programming with Arrow in Kotlin

Functional Programming with Arrow in Kotlin

GIDS 2019: https://www.developermarch.com/developersummit/session.html?insert=Raghunath

With a rising trend in programming languages adding more and more functional capabilities, developers are working at a much higher level of abstraction. The declarative style of programming allows us to write readable and maintainable code that focuses on "what" (larger picture) rather than "how" (nuts and bolts). Functional programming also promotes immutability by default which makes dealing with concurrency an easy and a fun affair. Kotlin already supports some of these features like functions as first-class citizens, lambdas, anonymous functions, immutability, persistent collections, explicit nullable and non-nullable types, declarative constructs, etc., However, these features lack capabilities offered by purely functional languages.

Arrow is a Kotlin library that pushes the envelope further by introducing typeclasses, functional data types, optics, etc., It achieves this by clever usage of Kotlin language features and by generating code using annotation processors.

This talk will walk you through several ideas and code examples that will help you get started with functional programming using Arrow.

Audience will be able to:
- Use functional data types from the Arrow library.
- Use functional programming patterns.
- Solve problems using functional ideas and gradually move away from imperative programming.
- Deal with immutability and use optics to modify deeply nested data structures efficiently.

Ragunath Jawahar

April 23, 2019
Tweet

More Decks by Ragunath Jawahar

Other Decks in Programming

Transcript

  1. Functional Programming with
    Arrow in Kotlin
    @ragunathjawahar • Obvious (previously, Uncommon Bangalore)

    View Slide

  2. fun findFirst(array: Array, key: Char): Int {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }

    View Slide

  3. fun findFirst(array: Array, key: Char): Int {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }

    View Slide

  4. fun findFirst(array: Array, key: Char): Int {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }

    View Slide

  5. fun findFirst(array: Array, key: Char): Int {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }

    View Slide

  6. fun findFirst(array: Array, key: Char): Int {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }

    View Slide

  7. fun findFirst(array: Array, key: Char): Int {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }

    View Slide

  8. fun findFirst(array: Array, key: Char): Int {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }

    View Slide

  9. fun findFirst(array: Array, key: Char): Int {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }

    View Slide

  10. fun findFirst(array: Array, key: Char): Int {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }

    View Slide

  11. fun findFirst(array: Array, key: Char): Int {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }

    View Slide

  12. fun findFirst(array: Array, key: Char): Int {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }

    View Slide

  13. fun findFirst(array: Array, key: Char): Int {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }

    View Slide

  14. fun findFirst(array: Array, key: Char): Index {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }
    typealias Index = Int

    View Slide

  15. fun findFirst(array: Array, key: Char): Index {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }
    typealias Index = Int

    View Slide

  16. fun findFirst(array: Array, key: Char): Index {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }
    typealias Index = Int

    View Slide

  17. fun findFirst(array: Array, key: Char): Index {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }
    typealias Index = Int
    // findFirst(chars, ‘e’) != -1

    View Slide

  18. fun findFirst(array: Array, key: Char): Index {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }
    typealias Index = Int
    // findFirst(chars, ‘e’) != -1

    View Slide

  19. fun findFirst(array: Array, key: Char): Index {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }
    typealias Index = Int

    View Slide

  20. fun findFirst(array: Array, key: Char): Index? {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return null
    }
    typealias Index = Int

    View Slide

  21. fun findFirst(array: Array, key: Char): Option {
    for (i in array.indices) {
    if (array[i] == key) return Some(i)
    }
    return None
    }
    typealias Index = Int

    View Slide

  22. fun findFirst(array: Array, key: Char): Option {
    for (i in array.indices) {
    if (array[i] == key) return Some(i)
    }
    return None
    }
    typealias Index = Int
    // absence
    // presence

    View Slide

  23. fun findFirst(array: Array, key: Char): Option {
    for (i in array.indices) {
    if (array[i] == key) return Some(i)
    }
    return None
    }
    typealias Index = Int

    View Slide

  24. fun findFirst(array: Array, key: Char): Option {
    for (i in array.indices) {
    if (array[i] == key) return Some(i)
    }
    return None
    }
    typealias Index = Int

    View Slide

  25. fun findFirst(array: Array, key: Char): Option {
    for (i in array.indices) {
    if (array[i] == key) return Some(i)
    }
    return None
    }
    typealias Index = Int

    View Slide

  26. fun findFirst(array: Array, key: A): Option {
    for (i in array.indices) {
    if (array[i] == key) return Some(i)
    }
    return None
    }
    typealias Index = Int

    View Slide

  27. fun findFirst(array: Array, key: A): Option {
    for (i in array.indices) {
    if (array[i] == key) return Some(i)
    }
    return None
    }
    typealias Index = Int

    View Slide

  28. fun findFirst(array: Array, key: A): Option {
    for (i in array.indices) {
    if (array[i] == key) return Some(i)
    }
    return None
    }
    typealias Index = Int

    View Slide

  29. fun findFirst(array: Array, p: (A) -> Boolean): Option {
    for (i in array.indices) {
    if (p(array[i])) return Some(i)
    }
    return None
    }
    typealias Index = Int

    View Slide

  30. fun findFirst(array: Array, p: (A) -> Boolean): Option {
    for (i in array.indices) {
    if (p(array[i])) return Some(i)
    }
    return None
    }
    typealias Index = Int
    // findFirst(people, { it.firstName == “Ajay” })

    View Slide

  31. fun findFirst(array: Array, p: (A) -> Boolean): Option {
    for (i in array.indices) {
    if (p(array[i])) return Some(i)
    }
    return None
    }
    typealias Index = Int
    // findFirst(people) { it.firstName == “Ajay” }

    View Slide

  32. fun findFirst(array: Array, p: (A) -> Boolean): Option {
    for (i in array.indices) {
    if (p(array[i])) return Some(i)
    }
    return None
    }
    typealias Index = Int

    View Slide

  33. fun findFirst(array: Array, p: (A) -> Boolean): Option {
    for (i in array.indices) {
    if (p(array[i])) return Some(i)
    }
    return None
    }
    typealias Index = Int

    View Slide

  34. fun findFirst(array: Array, p: (A) -> Boolean): Option {
    for (i in array.indices) {
    if (p(array[i])) return Some(i)
    }
    return None
    }
    typealias Index = Int
    // findFirst(people) { it.firstName == “Ajay” }

    View Slide

  35. fun Array.findFirst(p:,(A) -> Boolean): Option {
    for (i in this.indices) {
    if (p(this[i])) return Some(i)
    }
    return None
    }
    typealias Index = Int
    // people.findFirst { it.firstName == “Ajay” }

    View Slide

  36. fun Array.findFirst(p:,(A) -> Boolean): Option {
    for (i in this.indices) {
    if (p(this[i])) return Some(i)
    }
    return None
    }
    typealias Index = Int

    View Slide

  37. fun Array.findFirst(p:,(A) -> Boolean): Option {
    for (i in this.indices) {
    if (p(this[i])) return Some(i)
    }
    return None
    }
    fun findFirst(array: Array, key: Char): Int {
    for (i in array.indices) {
    if (array[i] == key) return i
    }
    return -1
    }

    View Slide

  38. fun findFirst(array: Array, p:,(A) -> Boolean): Option {
    tailrec fun go(array: Array, index: Index): Option {
    return when {
    index == array.size -> None
    p(array[index]) -> Some(index)
    else -> go(array, index + 1)
    }
    }
    return go(array, 0)
    }
    But!

    View Slide

  39. fun findFirst(array: Array, p:,(A) -> Boolean): Option {
    tailrec fun go(array: Array, index: Index): Option {
    return when {
    index == array.size -> None
    p(array[index]) -> Some(index)
    else -> go(array, index + 1)
    }
    }
    return go(array, 0)
    }
    But!

    View Slide

  40. fun findFirst(array: Array, p:,(A) -> Boolean): Option {
    tailrec fun go(array: Array, index: Index): Option {
    return when {
    index == array.size -> None
    p(array[index]) -> Some(index)
    else -> go(array, index + 1)
    }
    }
    return go(array, 0)
    }
    But!

    View Slide

  41. fun findFirst(array: Array, p:,(A) -> Boolean): Option {
    tailrec fun go(array: Array, index: Index): Option {
    return when {
    index == array.size -> None
    p(array[index]) -> Some(index)
    else -> go(array, index + 1)
    }
    }
    return go(array, 0)
    }
    But!

    View Slide

  42. fun findFirst(array: Array, p:,(A) -> Boolean): Option {
    tailrec fun go(array: Array, index: Index): Option {
    return when {
    index == array.size -> None
    p(array[index]) -> Some(index)
    else -> go(array, index + 1)
    }
    }
    return go(array, 0)
    }
    But!

    View Slide

  43. fun findFirst(array: Array, p:,(A) -> Boolean): Option {
    tailrec fun go(array: Array, index: Index): Option {
    return when {
    index == array.size -> None
    p(array[index]) -> Some(index)
    else -> go(array, index + 1)
    }
    }
    return go(array, 0)
    }
    But!

    View Slide

  44. fun findFirst(array: Array, p:,(A) -> Boolean): Option {
    tailrec fun go(array: Array, index: Index): Option {
    return when {
    index == array.size -> None
    p(array[index]) -> Some(index)
    else -> go(array, index + 1)
    }
    }
    return go(array, 0)
    }
    But!

    View Slide

  45. fun findFirst(array: Array, p:,(A) -> Boolean): Option {
    tailrec fun go(array: Array, index: Index): Option {
    return when {
    index == array.size -> None
    p(array[index]) -> Some(index)
    else -> go(array, index + 1)
    }
    }
    return go(array, 0)
    }
    But!

    View Slide

  46. fun findFirst(array: Array, p:,(A) -> Boolean): Option {
    tailrec fun go(array: Array, index: Index): Option {
    return when {
    index == array.size -> None
    p(array[index]) -> Some(index)
    else -> go(array, index + 1)
    }
    }
    return go(array, 0)
    }
    But!

    View Slide

  47. fun findFirst(array: Array, p:,(A) -> Boolean): Option {
    tailrec fun go(array: Array, index: Index): Option {
    return when {
    index == array.size -> None
    p(array[index]) -> Some(index)
    else -> go(array, index + 1)
    }
    }
    return go(array, 0)
    }
    But!

    View Slide

  48. fun findFirst(array: Array, p:,(A) -> Boolean): Option {
    tailrec fun go(array: Array, index: Index): Option {
    return when {
    index == array.size -> None
    p(array[index]) -> Some(index)
    else -> go(array, index + 1)
    }
    }
    return go(array, 0)
    }
    But!

    View Slide

  49. fun findFirst(array: Array, p:,(A) -> Boolean): Option {
    tailrec fun go(array: Array, index: Index): Option {
    return when {
    index == array.size -> None
    p(array[index]) -> Some(index)
    else -> go(array, index + 1)
    }
    }
    return go(array, 0)
    }
    But!

    View Slide

  50. fun findFirst(array: Array, p:,(A) -> Boolean): Option {
    tailrec fun go(array: Array, index: Index): Option {
    return when {
    index == array.size -> None
    p(array[index]) -> Some(index)
    else -> go(array, index + 1)
    }
    }
    return go(array, 0)
    }
    But!

    View Slide

  51. fun findFirst(array: Array, p:,(A) -> Boolean): Option {
    tailrec fun go(array: Array, index: Index): Option {
    return when {
    index == array.size -> None
    p(array[index]) -> Some(index)
    else -> go(array, index + 1)
    }
    }
    return go(array, 0)
    }
    But!

    View Slide

  52. fun findFirst(array: Array, p:,(A) -> Boolean): Option {
    tailrec fun go(array: Array, index: Index): Option {
    return when {
    index == array.size -> None
    p(array[index]) -> Some(index)
    else -> go(array, index + 1)
    }
    }
    return go(array, 0)
    }
    But!

    View Slide

  53. Core Ideas

    View Slide

  54. Core Ideas
    • Purity

    • Referential Transparency

    • Immutability

    • Lazy Evaluation

    View Slide

  55. Notations

    View Slide

  56. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  57. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  58. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  59. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  60. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  61. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  62. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  63. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  64. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  65. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  66. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  67. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  68. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }
    // (a: Int, b: Int) -> Int

    View Slide

  69. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  70. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  71. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  72. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  73. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  74. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  75. fun add(a: Int, b: Int): Int = a + b
    val addRef: (Int, Int) -> Int = ::add
    val subtractLambda = { a: Int, b: Int -> a - b }

    View Slide

  76. val addRef: (Int, Int) -> Int = ::add
    addRef.invoke(4, 5)
    addRef(4, 5)

    View Slide

  77. Arrow Syntax
    compile "io.arrow-kt:arrow-syntax:$arrow_version"

    View Slide

  78. val bold: (String) -> String = { "$it" }
    val italic: (String) -> String = { "$it" }
    val boldItalic = bold compose italic
    val italicBold = bold forwardCompose italic
    Composition

    View Slide

  79. val bold: (String) -> String = { "$it" }
    val italic: (String) -> String = { "$it" }
    val boldItalic = bold compose italic
    val italicBold = bold forwardCompose italic
    Composition

    View Slide

  80. val bold: (String) -> String = { "$it" }
    val italic: (String) -> String = { "$it" }
    val boldItalic = bold compose italic
    val italicBold = bold forwardCompose italic
    Composition
    // bold(“Hello”)

    View Slide

  81. val bold: (String) -> String = { "$it" }
    val italic: (String) -> String = { "$it" }
    val boldItalic = bold compose italic
    val italicBold = bold forwardCompose italic
    Composition
    // Hello

    View Slide

  82. val bold: (String) -> String = { "$it" }
    val italic: (String) -> String = { "$it" }
    val boldItalic = bold compose italic
    val italicBold = bold forwardCompose italic
    Composition

    View Slide

  83. val bold: (String) -> String = { "$it" }
    val italic: (String) -> String = { "$it" }
    val boldItalic = bold compose italic
    val italicBold = bold forwardCompose italic
    Composition
    // italic(“Hello”)

    View Slide

  84. val bold: (String) -> String = { "$it" }
    val italic: (String) -> String = { "$it" }
    val boldItalic = bold compose italic
    val italicBold = bold forwardCompose italic
    Composition
    // Hello

    View Slide

  85. val bold: (String) -> String = { "$it" }
    val italic: (String) -> String = { "$it" }
    val boldItalic = bold compose italic
    val italicBold = bold forwardCompose italic
    Composition

    View Slide

  86. val bold: (String) -> String = { "$it" }
    val italic: (String) -> String = { "$it" }
    val boldItalic = bold compose italic
    val italicBold = bold forwardCompose italic
    Composition
    // boldItalic(“Hello”)

    View Slide

  87. val bold: (String) -> String = { "$it" }
    val italic: (String) -> String = { "$it" }
    val boldItalic = bold compose italic
    val italicBold = bold forwardCompose italic
    Composition
    // Hello

    View Slide

  88. val bold: (String) -> String = { "$it" }
    val italic: (String) -> String = { "$it" }
    val boldItalic = bold compose italic
    val italicBold = bold forwardCompose italic
    Composition

    View Slide

  89. val bold: (String) -> String = { "$it" }
    val italic: (String) -> String = { "$it" }
    val boldItalic = bold compose italic
    val italicBold = bold forwardCompose italic
    Composition
    // italicBold(“Hello”)

    View Slide

  90. val bold: (String) -> String = { "$it" }
    val italic: (String) -> String = { "$it" }
    val boldItalic = bold compose italic
    val italicBold = bold forwardCompose italic
    Composition
    // Hello

    View Slide

  91. val bold: (String) -> String = { "$it" }
    val italic: (String) -> String = { "$it" }
    val boldItalic = bold compose italic
    val italicBold = bold forwardCompose italic
    Composition

    View Slide

  92. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application

    View Slide

  93. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application

    View Slide

  94. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application

    View Slide

  95. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application

    View Slide

  96. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application

    View Slide

  97. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application

    View Slide

  98. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application

    View Slide

  99. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application

    View Slide

  100. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application
    // x2(10)

    View Slide

  101. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application
    // 20

    View Slide

  102. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application

    View Slide

  103. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application

    View Slide

  104. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application

    View Slide

  105. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application

    View Slide

  106. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application

    View Slide

  107. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application

    View Slide

  108. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application
    // x5(10)

    View Slide

  109. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application
    // 50

    View Slide

  110. fun multiply(a: Int, b: Int): Int = a * b
    val x2: (Int) -> Int = ::multiply.partially1(2)
    val x5: (Int) -> Int = ::multiply.partially1(5)
    Partial Application

    View Slide

  111. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  112. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  113. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  114. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  115. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  116. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  117. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  118. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  119. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  120. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  121. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  122. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  123. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  124. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  125. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  126. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }
    // findCat(animals)

    View Slide

  127. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  128. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  129. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  130. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  131. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  132. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  133. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog } // findDog(animals)

    View Slide

  134. Reverse
    fun findFirst(
    animals: List, predicate: (Animal) -> Boolean
    ): Option { /* … */ }
    val findCat: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Cat }
    val findDog: (List) -> Option =
    ::findFirst.reverse().partially1 { it is Dog }

    View Slide

  135. Logical Complement
    val onlyCats: (Animal) -> Boolean = { it is Cat }
    val allCats = filter(animals, onlyCats)
    val noCats = onlyCats.complement()
    val allExceptCats = filter(animals, noCats)

    View Slide

  136. Logical Complement
    val onlyCats: (Animal) -> Boolean = { it is Cat }
    val allCats = filter(animals, onlyCats)
    val noCats = onlyCats.complement()
    val allExceptCats = filter(animals, noCats)

    View Slide

  137. Logical Complement
    val onlyCats: (Animal) -> Boolean = { it is Cat }
    val allCats = filter(animals, onlyCats)
    val noCats = onlyCats.complement()
    val allExceptCats = filter(animals, noCats)

    View Slide

  138. Logical Complement
    val onlyCats: (Animal) -> Boolean = { it is Cat }
    val allCats = filter(animals, onlyCats)
    val noCats = onlyCats.complement()
    val allExceptCats = filter(animals, noCats)

    View Slide

  139. Logical Complement
    val onlyCats: (Animal) -> Boolean = { it is Cat }
    val allCats = filter(animals, onlyCats)
    val noCats = onlyCats.complement()
    val allExceptCats = filter(animals, noCats)

    View Slide

  140. Logical Complement
    val onlyCats: (Animal) -> Boolean = { it is Cat }
    val allCats = filter(animals, onlyCats)
    val noCats = onlyCats.complement()
    val allExceptCats = filter(animals, noCats)

    View Slide

  141. Logical Complement
    val onlyCats: (Animal) -> Boolean = { it is Cat }
    val allCats = filter(animals, onlyCats)
    val noCats = onlyCats.complement()
    val allExceptCats = filter(animals, noCats)

    View Slide

  142. Logical Complement
    val onlyCats: (Animal) -> Boolean = { it is Cat }
    val allCats = filter(animals, onlyCats)
    val noCats = onlyCats.complement()
    val allExceptCats = filter(animals, noCats)

    View Slide

  143. Logical Complement
    val onlyCats: (Animal) -> Boolean = { it is Cat }
    val allCats = filter(animals, onlyCats)
    val noCats = onlyCats.complement()
    val allExceptCats = filter(animals, noCats)

    View Slide

  144. Currying (1/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    volume(10, 10, 1)
    val curriedVolume: (width: Int) -> (height: Int) -> (length: Int) -> Int =
    ::volume.curried()
    curriedVolume(10)(10)(1)

    View Slide

  145. Currying (1/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    volume(10, 10, 1)
    val curriedVolume: (width: Int) -> (height: Int) -> (length: Int) -> Int =
    ::volume.curried()
    curriedVolume(10)(10)(1)

    View Slide

  146. Currying (1/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    volume(10, 10, 1)
    val curriedVolume: (width: Int) -> (height: Int) -> (length: Int) -> Int =
    ::volume.curried()
    curriedVolume(10)(10)(1)

    View Slide

  147. Currying (1/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    volume(10, 10, 1)
    val curriedVolume: (width: Int) -> (height: Int) -> (length: Int) -> Int =
    ::volume.curried()
    curriedVolume(10)(10)(1)

    View Slide

  148. Currying (1/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    volume(10, 10, 1)
    val curriedVolume: (width: Int) -> (height: Int) -> (length: Int) -> Int =
    ::volume.curried()
    curriedVolume(10)(10)(1)

    View Slide

  149. Currying (1/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    volume(10, 10, 1)
    val curriedVolume: (width: Int) -> (height: Int) -> (length: Int) -> Int =
    ::volume.curried()
    curriedVolume(10)(10)(1)

    View Slide

  150. Currying (1/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    volume(10, 10, 1)
    val curriedVolume: (width: Int) -> (height: Int) -> (length: Int) -> Int =
    ::volume.curried()
    curriedVolume(10)(10)(1)

    View Slide

  151. Currying (1/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    volume(10, 10, 1)
    val curriedVolume: (width: Int) -> (height: Int) -> (length: Int) -> Int =
    ::volume.curried()
    curriedVolume(10)(10)(1)
    // 100

    View Slide

  152. Currying (1/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    volume(10, 10, 1)
    val curriedVolume: (width: Int) -> (height: Int) -> (length: Int) -> Int =
    ::volume.curried()
    curriedVolume(10)(10)(1)

    View Slide

  153. Currying (1/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    volume(10, 10, 1)
    val curriedVolume: (width: Int) -> (height: Int) -> (length: Int) -> Int =
    ::volume.curried()
    curriedVolume(10)(10)(1)

    View Slide

  154. Currying (1/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    volume(10, 10, 1)
    val curriedVolume: (width: Int) -> (height: Int) -> (length: Int) -> Int =
    ::volume.curried()
    curriedVolume(10)(10)(1)

    View Slide

  155. Currying (1/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    volume(10, 10, 1)
    val curriedVolume: (width: Int) -> (height: Int) -> (length: Int) -> Int =
    ::volume.curried()
    curriedVolume(10)(10)(1)

    View Slide

  156. Currying (1/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    volume(10, 10, 1)
    val curriedVolume: (width: Int) -> (height: Int) -> (length: Int) -> Int =
    ::volume.curried()
    curriedVolume(10)(10)(1)

    View Slide

  157. Currying (1/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    volume(10, 10, 1)
    val curriedVolume: (width: Int) -> (height: Int) -> (length: Int) -> Int =
    ::volume.curried()
    curriedVolume(10)(10)(1)

    View Slide

  158. Currying (1/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    volume(10, 10, 1)
    val curriedVolume: (width: Int) -> (height: Int) -> (length: Int) -> Int =
    ::volume.curried()
    curriedVolume(10)(10)(1)

    View Slide

  159. Currying (1/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    volume(10, 10, 1)
    val curriedVolume: (width: Int) -> (height: Int) -> (length: Int) -> Int =
    ::volume.curried()
    curriedVolume(10)(10)(1)

    View Slide

  160. Currying (1/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    volume(10, 10, 1)
    val curriedVolume: (width: Int) -> (height: Int) -> (length: Int) -> Int =
    ::volume.curried()
    curriedVolume(10)(10)(1) // 100

    View Slide

  161. Currying (1/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    volume(10, 10, 1)
    val curriedVolume: (width: Int) -> (height: Int) -> (length: Int) -> Int =
    ::volume.curried()
    curriedVolume(10)(10)(1)

    View Slide

  162. Currying (2/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    val area = ::volume
    .reverse().curried()(1)
    .uncurried().reverse()
    area(10, 10)

    View Slide

  163. Currying (2/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    val area = ::volume
    .reverse().curried()(1)
    .uncurried().reverse()
    area(10, 10)

    View Slide

  164. Currying (2/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    val area = ::volume
    .reverse().curried()(1)
    .uncurried().reverse()
    area(10, 10)

    View Slide

  165. Currying (2/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    val area = ::volume
    .reverse().curried()(1)
    .uncurried().reverse()
    area(10, 10)
    // (width, height, length)

    View Slide

  166. Currying (2/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    val area = ::volume
    .reverse().curried()(1)
    .uncurried().reverse()
    area(10, 10)
    // (length, height, width)

    View Slide

  167. Currying (2/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    val area = ::volume
    .reverse().curried()(1)
    .uncurried().reverse()
    area(10, 10)
    // (length) -> (height) -> (width)

    View Slide

  168. Currying (2/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    val area = ::volume
    .reverse().curried()(1)
    .uncurried().reverse()
    area(10, 10)
    // (height) -> (width)

    View Slide

  169. Currying (2/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    val area = ::volume
    .reverse().curried()(1)
    .uncurried().reverse()
    area(10, 10)
    // (height, width)

    View Slide

  170. Currying (2/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    val area = ::volume
    .reverse().curried()(1)
    .uncurried().reverse()
    area(10, 10)
    // (width, height)

    View Slide

  171. Currying (2/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    val area = ::volume
    .reverse().curried()(1)
    .uncurried().reverse()
    area(10, 10)

    View Slide

  172. Currying (2/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    val area = ::volume
    .reverse().curried()(1)
    .uncurried().reverse()
    area(10, 10)

    View Slide

  173. Currying (2/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    val area = ::volume
    .reverse().curried()(1)
    .uncurried().reverse()
    area(10, 10) // 100

    View Slide

  174. Currying (2/2)
    fun volume(width: Int, height: Int, length: Int): Int =
    width * height * length
    val area = ::volume
    .reverse().curried()(1)
    .uncurried().reverse()
    area(10, 10)

    View Slide

  175. More…
    • memoize() // FunctionN
    • firstOption() // Array, Sequence, and Iterable
    • flatten() - tail() - prependTo(List) // List
    • plus(C) // TupleN
    • paired() - tripled() // FunctionN
    • pipe() // FunctionN

    View Slide

  176. Data Types
    compile “io.arrow-kt:arrow-core-data:$arrow_version”

    View Slide

  177. Data Types
    • Option
    • Either
    • Try
    • Validated
    • Eval

    View Slide

  178. Option
    sealed class Option {
    object None : Option()
    data class Some(val t: T) : Option()
    }
    Option is an Algebraic Data Type that is used to model the absence of value. In Kotlin
    they are encoded with sealed class hierarchies.

    View Slide

  179. Option
    sealed class Option {
    object None : Option()
    data class Some(val t: T) : Option()
    }
    Option is an Algebraic Data Type that is used to model the absence of value. In Kotlin
    they are encoded with sealed class hierarchies.

    View Slide

  180. Option
    sealed class Option {
    object None : Option()
    data class Some(val t: T) : Option()
    }
    Option is an Algebraic Data Type that is used to model the absence of value. In Kotlin
    they are encoded with sealed class hierarchies.

    View Slide

  181. Option
    sealed class Option {
    object None : Option()
    data class Some(val t: T) : Option()
    }
    Option is an Algebraic Data Type that is used to model the absence of value. In Kotlin
    they are encoded with sealed class hierarchies.

    View Slide

  182. Option
    sealed class Option {
    object None : Option()
    data class Some(val t: T) : Option()
    }
    Option is an Algebraic Data Type that is used to model the absence of value. In Kotlin
    they are encoded with sealed class hierarchies.

    View Slide

  183. Option (Construction)
    val intOption: Option = Option(1)
    val intOption: Option = None
    val intOption: Option = Option.fromNullable(a) // a: Int?
    val intOption: Option = 1.some()
    val intOption: Option = none()

    View Slide

  184. Option (Construction)
    val intOption: Option = Option(1)
    val intOption: Option = None
    val intOption: Option = Option.fromNullable(a) // a: Int?
    val intOption: Option = 1.some()
    val intOption: Option = none()

    View Slide

  185. Option (Construction)
    val intOption: Option = Option(1)
    val intOption: Option = None
    val intOption: Option = Option.fromNullable(a) // a: Int?
    val intOption: Option = 1.some()
    val intOption: Option = none()

    View Slide

  186. Option (Construction)
    val intOption: Option = Option(1)
    val intOption: Option = None
    val intOption: Option = Option.fromNullable(a) // a: Int?
    val intOption: Option = 1.some()
    val intOption: Option = none()

    View Slide

  187. Option (Construction)
    val intOption: Option = Option(1)
    val intOption: Option = None
    val intOption: Option = Option.fromNullable(a) // a: Int?
    val intOption: Option = 1.some()
    val intOption: Option = none()

    View Slide

  188. Option (Construction)
    val intOption: Option = Option(1)
    val intOption: Option = None
    val intOption: Option = Option.fromNullable(a) // a: Int?
    val intOption: Option = 1.some()
    val intOption: Option = none()

    View Slide

  189. Option (Construction)
    val intOption: Option = Option(1)
    val intOption: Option = None
    val intOption: Option = Option.fromNullable(a) // a: Int?
    val intOption: Option = 1.some()
    val intOption: Option = none()

    View Slide

  190. Option (Extraction)
    val intOption: Option = Option(1)
    val nullableResult: Int? = intOption.orNull()
    val result: Int = intOption.getOrElse { 0 }

    View Slide

  191. Option (Extraction)
    val intOption: Option = Option(1)
    val nullableResult: Int? = intOption.orNull()
    val result: Int = intOption.getOrElse { 0 }

    View Slide

  192. Option (Extraction)
    val intOption: Option = Option(1)
    val nullableResult: Int? = intOption.orNull()
    val result: Int = intOption.getOrElse { 0 }

    View Slide

  193. Option (Extraction)
    val intOption: Option = Option(1)
    val nullableResult: Int? = intOption.orNull()
    val result: Int = intOption.getOrElse { 0 }

    View Slide

  194. Option (Extraction)
    val intOption: Option = Option(1)
    val nullableResult: Int? = intOption.orNull()
    val result: Int = intOption.getOrElse { 0 }

    View Slide

  195. Option (Extraction - when)
    val intOption: Option = Option(1)
    when (intOption) {
    is None -> 0
    is Some -> intOption.t
    } // Some(1)

    View Slide

  196. Option (Extraction - when)
    val intOption: Option = Option(1)
    when (intOption) {
    is None -> 0
    is Some -> intOption.t
    } // Some(1)

    View Slide

  197. Option (Extraction - when)
    val intOption: Option = Option(1)
    when (intOption) {
    is None -> 0
    is Some -> intOption.t
    } // Some(1)

    View Slide

  198. Option (Extraction - when)
    val intOption: Option = Option(1)
    when (intOption) {
    is None -> 0
    is Some -> intOption.t
    } // Some(1)

    View Slide

  199. Option (Extraction - when)
    val intOption: Option = Option(1)
    when (intOption) {
    is None -> 0
    is Some -> intOption.t
    } // Some(1)

    View Slide

  200. Option (Extraction - when)
    val intOption: Option = Option(1)
    when (intOption) {
    is None -> 0
    is Some -> intOption.t
    } // Some(1)

    View Slide

  201. Option (Extraction - when)
    val intOption: Option = Option(1)
    when (intOption) {
    is None -> 0
    is Some -> intOption.t
    } // Some(1)

    View Slide

  202. Option (Extraction - fold)
    val intOption: Option = Option(1)
    intOption.fold(
    { 0 },
    { it + 1 }
    ) // Some(2)

    View Slide

  203. Option (Extraction - fold)
    val intOption: Option = Option(1)
    intOption.fold(
    { 0 },
    { it + 1 }
    ) // Some(2)

    View Slide

  204. Option (Extraction - fold)
    val intOption: Option = Option(1)
    intOption.fold(
    { 0 },
    { it + 1 }
    ) // Some(2)

    View Slide

  205. Option (Extraction - fold)
    val intOption: Option = Option(1)
    intOption.fold(
    { 0 },
    { it + 1 }
    ) // Some(2)

    View Slide

  206. Option (Extraction - fold)
    val intOption: Option = Option(1)
    intOption.fold(
    { 0 },
    { it + 1 }
    ) // Some(2)

    View Slide

  207. Option (Extraction - fold)
    val intOption: Option = Option(1)
    intOption.fold(
    { 0 },
    { it + 1 }
    ) // Some(2)

    View Slide

  208. Option (Extraction - fold)
    val intOption: Option = Option(1)
    intOption.fold(
    { 0 },
    { it + 1 }
    ) // Some(2)

    View Slide

  209. Option (map)
    val intOption: Option = Option(1)
    intOption.map { it * 2 } // Some(2)
    val intOption: Option = None
    intOption.map { it * 2 } // None

    View Slide

  210. Option (map)
    val intOption: Option = Option(1)
    intOption.map { it * 2 } // Some(2)
    val intOption: Option = None
    intOption.map { it * 2 } // None

    View Slide

  211. Option (map)
    val intOption: Option = Option(1)
    intOption.map { it * 2 } // Some(2)
    val intOption: Option = None
    intOption.map { it * 2 } // None

    View Slide

  212. Option (map)
    val intOption: Option = Option(1)
    intOption.map { it * 2 } // Some(2)
    val intOption: Option = None
    intOption.map { it * 2 } // None

    View Slide

  213. Option (map)
    val intOption: Option = Option(1)
    intOption.map { it * 2 } // Some(2)
    val intOption: Option = None
    intOption.map { it * 2 } // None

    View Slide

  214. Option (map)
    val intOption: Option = Option(1)
    intOption.map { it * 2 } // Some(2)
    val intOption: Option = None
    intOption.map { it * 2 } // None

    View Slide

  215. Option (map)
    val intOption: Option = Option(1)
    intOption.map { it * 2 } // Some(2)
    val intOption: Option = None
    intOption.map { it * 2 } // None

    View Slide

  216. Option (map)
    val intOption: Option = Option(1)
    intOption.map { it * 2 } // Some(2)
    val intOption: Option = None
    intOption.map { it * 2 } // None

    View Slide

  217. Option (flatMap)
    val oneOption: Option = Option(1)
    val twoOption: Option = Option(2)
    oneOption.flatMap { one ->
    twoOption.map { two ->
    one + two
    }
    } // Some(3)

    View Slide

  218. Option (flatMap)
    val oneOption: Option = Option(1)
    val twoOption: Option = Option(2)
    oneOption.flatMap { one ->
    twoOption.map { two ->
    one + two
    }
    } // Some(3)

    View Slide

  219. Option (flatMap)
    val oneOption: Option = Option(1)
    val twoOption: Option = Option(2)
    oneOption.flatMap { one ->
    twoOption.map { two ->
    one + two
    }
    } // Some(3)

    View Slide

  220. Option (flatMap)
    val oneOption: Option = Option(1)
    val twoOption: Option = Option(2)
    oneOption.flatMap { one ->
    twoOption.map { two ->
    one + two
    }
    } // Some(3)

    View Slide

  221. Option (flatMap)
    val oneOption: Option = Option(1)
    val twoOption: Option = Option(2)
    oneOption.flatMap { one ->
    twoOption.map { two ->
    one + two
    }
    } // Some(3)

    View Slide

  222. Option (flatMap)
    val oneOption: Option = Option(1)
    val twoOption: Option = Option(2)
    oneOption.flatMap { one ->
    twoOption.map { two ->
    one + two
    }
    } // Some(3)

    View Slide

  223. Option (flatMap)
    val oneOption: Option = Option(1)
    val twoOption: Option = Option(2)
    oneOption.flatMap { one ->
    twoOption.map { two ->
    one + two
    }
    } // Some(3)

    View Slide

  224. Option (flatMap)
    val oneOption: Option = Option(1)
    val twoOption: Option = None
    oneOption.flatMap { one ->
    twoOption.map { two ->
    one + two
    }
    } // None

    View Slide

  225. Option (flatMap)
    val oneOption: Option = Option(1)
    val twoOption: Option = None
    oneOption.flatMap { one ->
    twoOption.map { two ->
    one + two
    }
    } // None

    View Slide

  226. Option (flatMap)
    val oneOption: Option = Option(1)
    val twoOption: Option = None
    oneOption.flatMap { one ->
    twoOption.map { two ->
    one + two
    }
    } // None

    View Slide

  227. Option (Monad Binding)
    val oneOption: Option = Option(1)
    val twoOption: Option = Option(2)
    Option.monad().binding {
    val one = oneOption.bind()
    val two = twoOption.bind()
    one + two
    }.fix() // Some(3)

    View Slide

  228. Option (Monad Binding)
    val oneOption: Option = Option(1)
    val twoOption: Option = Option(2)
    Option.monad().binding {
    val one = oneOption.bind()
    val two = twoOption.bind()
    one + two
    }.fix() // Some(3)

    View Slide

  229. Option (Monad Binding)
    val oneOption: Option = Option(1)
    val twoOption: Option = Option(2)
    Option.monad().binding {
    val one = oneOption.bind()
    val two = twoOption.bind()
    one + two
    }.fix() // Some(3)

    View Slide

  230. Option (Monad Binding)
    val oneOption: Option = Option(1)
    val twoOption: Option = Option(2)
    Option.monad().binding {
    val one = oneOption.bind()
    val two = twoOption.bind()
    one + two
    }.fix() // Some(3)

    View Slide

  231. Option (Monad Binding)
    val oneOption: Option = Option(1)
    val twoOption: Option = Option(2)
    Option.monad().binding {
    val one = oneOption.bind()
    val two = twoOption.bind()
    one + two
    }.fix() // Some(3)

    View Slide

  232. Option (Monad Binding)
    val oneOption: Option = Option(1)
    val twoOption: Option = Option(2)
    Option.monad().binding {
    val one = oneOption.bind()
    val two = twoOption.bind()
    one + two
    }.fix() // Some(3)

    View Slide

  233. Option (Monad Binding)
    val oneOption: Option = Option(1)
    val twoOption: Option = Option(2)
    Option.monad().binding {
    val one = oneOption.bind()
    val two = twoOption.bind()
    one + two
    }.fix() // Some(3)

    View Slide

  234. Option (Monad Binding)
    val oneOption: Option = Option(1)
    val twoOption: Option = Option(2)
    Option.monad().binding {
    val one = oneOption.bind()
    val two = twoOption.bind()
    one + two
    }.fix() // Some(3)

    View Slide

  235. Option (Monad Binding)
    val oneOption: Option = Option(1)
    val twoOption: Option = Option(2)
    Option.monad().binding {
    val one = oneOption.bind()
    val two = twoOption.bind()
    one + two
    }.fix() // Some(3)

    View Slide

  236. Option (Monad Binding)
    val oneOption: Option = Option(1)
    val twoOption: Option = None
    Option.monad().binding {
    val one = oneOption.bind()
    val two = twoOption.bind()
    one + two
    }.fix() // None

    View Slide

  237. Option (Monad Binding)
    val oneOption: Option = Option(1)
    val twoOption: Option = None
    Option.monad().binding {
    val one = oneOption.bind()
    val two = twoOption.bind()
    one + two
    }.fix() // None

    View Slide

  238. Option (Monad Binding)
    val oneOption: Option = Option(1)
    val twoOption: Option = None
    Option.monad().binding {
    val one = oneOption.bind()
    val two = twoOption.bind()
    one + two
    }.fix() // None

    View Slide

  239. Option (Applicative Builder)
    val maybeEspresso: Option = Option(Espresso(0.3))
    val maybeMilkOption: Option = Option(Milk(0.3))
    val foamOption: Option = Option(Foam(0.3))
    Option.applicative()
    .map(maybeEspresso, maybeMilk, maybeFoam) { (espresso, milk, foam) ->
    Cappuccino(espresso, milk, foam)
    }.fix()
    // Some(Cappuccino(espresso=Espresso(%=0.3), milk=Milk(%=0.3),
    // foam=Foam(%=0.3)))

    View Slide

  240. Option (Applicative Builder)
    val maybeEspresso: Option = Option(Espresso(0.3))
    val maybeMilkOption: Option = Option(Milk(0.3))
    val foamOption: Option = Option(Foam(0.3))
    Option.applicative()
    .map(maybeEspresso, maybeMilk, maybeFoam) { (espresso, milk, foam) ->
    Cappuccino(espresso, milk, foam)
    }.fix()
    // Some(Cappuccino(espresso=Espresso(%=0.3), milk=Milk(%=0.3),
    // foam=Foam(%=0.3)))

    View Slide

  241. Option (Applicative Builder)
    val maybeEspresso: Option = Option(Espresso(0.3))
    val maybeMilkOption: Option = Option(Milk(0.3))
    val foamOption: Option = Option(Foam(0.3))
    Option.applicative()
    .map(maybeEspresso, maybeMilk, maybeFoam) { (espresso, milk, foam) ->
    Cappuccino(espresso, milk, foam)
    }.fix()
    // Some(Cappuccino(espresso=Espresso(%=0.3), milk=Milk(%=0.3),
    // foam=Foam(%=0.3)))

    View Slide

  242. Option (Applicative Builder)
    val maybeEspresso: Option = Option(Espresso(0.3))
    val maybeMilkOption: Option = Option(Milk(0.3))
    val foamOption: Option = Option(Foam(0.3))
    Option.applicative()
    .map(maybeEspresso, maybeMilk, maybeFoam) { (espresso, milk, foam) ->
    Cappuccino(espresso, milk, foam)
    }.fix()
    // Some(Cappuccino(espresso=Espresso(%=0.3), milk=Milk(%=0.3),
    // foam=Foam(%=0.3)))

    View Slide

  243. Option (Applicative Builder)
    val maybeEspresso: Option = Option(Espresso(0.3))
    val maybeMilkOption: Option = Option(Milk(0.3))
    val foamOption: Option = Option(Foam(0.3))
    Option.applicative()
    .map(maybeEspresso, maybeMilk, maybeFoam) { (espresso, milk, foam) ->
    Cappuccino(espresso, milk, foam)
    }.fix()
    // Some(Cappuccino(espresso=Espresso(%=0.3), milk=Milk(%=0.3),
    // foam=Foam(%=0.3)))

    View Slide

  244. Option (Applicative Builder)
    val maybeEspresso: Option = Option(Espresso(0.3))
    val maybeMilkOption: Option = Option(Milk(0.3))
    val foamOption: Option = Option(Foam(0.3))
    Option.applicative()
    .map(maybeEspresso, maybeMilk, maybeFoam) { (espresso, milk, foam) ->
    Cappuccino(espresso, milk, foam)
    }.fix()
    // Some(Cappuccino(espresso=Espresso(%=0.3), milk=Milk(%=0.3),
    // foam=Foam(%=0.3)))

    View Slide

  245. Option (Applicative Builder)
    val maybeEspresso: Option = Option(Espresso(0.3))
    val maybeMilkOption: Option = Option(Milk(0.3))
    val foamOption: Option = Option(Foam(0.3))
    Option.applicative()
    .map(maybeEspresso, maybeMilk, maybeFoam) { (espresso, milk, foam) ->
    Cappuccino(espresso, milk, foam)
    }.fix()
    // Some(Cappuccino(espresso=Espresso(%=0.3), milk=Milk(%=0.3),
    // foam=Foam(%=0.3)))

    View Slide

  246. Option (Applicative Builder)
    val maybeEspresso: Option = Option(Espresso(0.3))
    val maybeMilkOption: Option = Option(Milk(0.3))
    val foamOption: Option = Option(Foam(0.3))
    Option.applicative()
    .map(maybeEspresso, maybeMilk, maybeFoam) { (espresso, milk, foam) ->
    Cappuccino(espresso, milk, foam)
    }.fix()
    // Some(Cappuccino(espresso=Espresso(%=0.3), milk=Milk(%=0.3),
    // foam=Foam(%=0.3)))

    View Slide

  247. Option (Applicative Builder)
    val maybeEspresso: Option = Option(Espresso(0.3))
    val maybeMilkOption: Option = Option(Milk(0.3))
    val foamOption: Option = Option(Foam(0.3))
    Option.applicative()
    .map(maybeEspresso, maybeMilk, maybeFoam) { (espresso, milk, foam) ->
    Cappuccino(espresso, milk, foam)
    }.fix()
    // Some(Cappuccino(espresso=Espresso(%=0.3), milk=Milk(%=0.3),
    // foam=Foam(%=0.3)))

    View Slide

  248. Option (Applicative Builder)
    val maybeEspresso: Option = Option(Espresso(0.3))
    val maybeMilkOption: Option = Option(Milk(0.3))
    val foamOption: Option = Option(Foam(0.3))
    Option.applicative()
    .map(maybeEspresso, maybeMilk, maybeFoam) { (espresso, milk, foam) ->
    Cappuccino(espresso, milk, foam)
    }.fix()
    // Some(Cappuccino(espresso=Espresso(%=0.3), milk=Milk(%=0.3),
    // foam=Foam(%=0.3)))

    View Slide

  249. Option (Applicative Builder)
    val maybeEspresso: Option = Option(Espresso(0.3))
    val maybeMilkOption: Option = Option(Milk(0.3))
    val foamOption: Option = Option(Foam(0.3))
    Option.applicative()
    .map(maybeEspresso, maybeMilk, maybeFoam) { (espresso, milk, foam) ->
    Cappuccino(espresso, milk, foam)
    }.fix()
    // Some(Cappuccino(espresso=Espresso(%=0.3), milk=Milk(%=0.3),
    // foam=Foam(%=0.3)))

    View Slide

  250. Option (Applicative Builder)
    val maybeEspresso: Option = Option(Espresso(0.3))
    val maybeMilkOption: Option = Option(Milk(0.3))
    val foamOption: Option = None
    Option.applicative()
    .map(maybeEspresso, maybeMilk, maybeFoam) { (espresso, milk, foam) ->
    Cappuccino(espresso, milk, foam)
    }.fix()
    // None

    View Slide

  251. Option (Applicative Builder)
    val maybeEspresso: Option = Option(Espresso(0.3))
    val maybeMilkOption: Option = Option(Milk(0.3))
    val foamOption: Option = None
    Option.applicative()
    .map(maybeEspresso, maybeMilk, maybeFoam) { (espresso, milk, foam) ->
    Cappuccino(espresso, milk, foam)
    }.fix()
    // None

    View Slide

  252. Option (Applicative Builder)
    val maybeEspresso: Option = Option(Espresso(0.3))
    val maybeMilkOption: Option = Option(Milk(0.3))
    val foamOption: Option = None
    Option.applicative()
    .map(maybeEspresso, maybeMilk, maybeFoam) { (espresso, milk, foam) ->
    Cappuccino(espresso, milk, foam)
    }.fix()
    // None

    View Slide

  253. Either
    sealed class Either {
    data class Left(val a: A) : Either()
    data class Right(val b: B) : Either()
    }
    Either is an Algebraic Data Type that is used to model a return type that may return one of
    two possible values.

    View Slide

  254. Either
    sealed class Either {
    data class Left(val a: A) : Either()
    data class Right(val b: B) : Either()
    }
    Either is an Algebraic Data Type that is used to model a return type that may return one of
    two possible values.

    View Slide

  255. Either
    sealed class Either {
    data class Left(val a: A) : Either()
    data class Right(val b: B) : Either()
    }
    Either is an Algebraic Data Type that is used to model a return type that may return one of
    two possible values.

    View Slide

  256. Either
    sealed class Either {
    data class Left(val a: A) : Either()
    data class Right(val b: B) : Either()
    }
    Either is an Algebraic Data Type that is used to model a return type that may return one of
    two possible values.

    View Slide

  257. Either
    sealed class Either {
    data class Left(val a: A) : Either()
    data class Right(val b: B) : Either()
    }
    Either is an Algebraic Data Type that is used to model a return type that may return one of
    two possible values.

    View Slide

  258. Either (Construction)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    val result: Either = Left(UnknownUser)
    val result: Either = 1.right()
    val result: Either = UnknownUser.left()

    View Slide

  259. Either (Construction)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    val result: Either = Left(UnknownUser)
    val result: Either = 1.right()
    val result: Either = UnknownUser.left()

    View Slide

  260. Either (Construction)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    val result: Either = Left(UnknownUser)
    val result: Either = 1.right()
    val result: Either = UnknownUser.left()

    View Slide

  261. Either (Construction)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    val result: Either = Left(UnknownUser)
    val result: Either = 1.right()
    val result: Either = UnknownUser.left()

    View Slide

  262. Either (Construction)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    val result: Either = Left(UnknownUser)
    val result: Either = 1.right()
    val result: Either = UnknownUser.left()

    View Slide

  263. Either (Construction)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    val result: Either = Left(UnknownUser)
    val result: Either = 1.right()
    val result: Either = UnknownUser.left()

    View Slide

  264. Either (Construction)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    val result: Either = Left(UnknownUser)
    val result: Either = 1.right()
    val result: Either = UnknownUser.left()

    View Slide

  265. Either (Extraction - when)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    when (result) {
    is Left -> 0
    is Right -> result.b
    } // Right(1)

    View Slide

  266. Either (Extraction - when)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    when (result) {
    is Left -> 0
    is Right -> result.b
    } // Right(1)

    View Slide

  267. Either (Extraction - when)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    when (result) {
    is Left -> 0
    is Right -> result.b
    } // Right(1)

    View Slide

  268. Either (Extraction - when)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    when (result) {
    is Left -> 0
    is Right -> result.b
    } // Right(1)

    View Slide

  269. Either (Extraction - when)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    when (result) {
    is Left -> 0
    is Right -> result.b
    } // Right(1) F

    View Slide

  270. Either (Extraction - when)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    when (result) {
    is Left -> 0
    is Right -> result.b
    } // Right(1)

    View Slide

  271. Either (Extraction - when)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    when (result) {
    is Left -> 0
    is Right -> result.b
    } // Right(1)

    View Slide

  272. Either (Extraction - fold)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    result.fold(
    { 0 },
    { it + 1 }
    ) // Right(2)

    View Slide

  273. Either (Extraction - fold)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    result.fold(
    { 0 },
    { it + 1 }
    ) // Right(2)

    View Slide

  274. Either (Extraction - fold)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    result.fold(
    { 0 },
    { it + 1 }
    ) // Right(2)

    View Slide

  275. Either (Extraction - fold)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    result.fold(
    { 0 },
    { it + 1 }
    ) // Right(2)

    View Slide

  276. Either (Extraction - fold)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    result.fold(
    { 0 },
    { it + 1 }
    ) // Right(2)

    View Slide

  277. Either (Extraction - fold)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    result.fold(
    { 0 },
    { it + 1 }
    ) // Right(2)

    View Slide

  278. Either (Extraction - fold)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    result.fold(
    { 0 },
    { it + 1 }
    ) // Right(2)

    View Slide

  279. Either (map)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    result.map { it * 2 } // Right(2)
    val result: Either = Left(UnknownUser)
    result.map { it * 2 } // Left(UnknownUser)

    View Slide

  280. Either (map)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    result.map { it * 2 } // Right(2)
    val result: Either = Left(UnknownUser)
    result.map { it * 2 } // Left(UnknownUser)

    View Slide

  281. Either (map)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    result.map { it * 2 } // Right(2)
    val result: Either = Left(UnknownUser)
    result.map { it * 2 } // Left(UnknownUser)

    View Slide

  282. Either (map)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    result.map { it * 2 } // Right(2)
    val result: Either = Left(UnknownUser)
    result.map { it * 2 } // Left(UnknownUser)

    View Slide

  283. Either (map)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    result.map { it * 2 } // Right(2)
    val result: Either = Left(UnknownUser)
    result.map { it * 2 } // Left(UnknownUser)

    View Slide

  284. Either (map)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    result.map { it * 2 } // Right(2)
    val result: Either = Left(UnknownUser)
    result.map { it * 2 } // Left(UnknownUser)

    View Slide

  285. Either (map)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    result.map { it * 2 } // Right(2)
    val result: Either = Left(UnknownUser)
    result.map { it * 2 } // Left(UnknownUser)

    View Slide

  286. Either (map)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    result.map { it * 2 } // Right(2)
    val result: Either = Left(UnknownUser)
    result.map { it * 2 } // Left(UnknownUser)

    View Slide

  287. Either (map)
    sealed class DomainError { /* ... */ }
    val result: Either = Right(1)
    result.map { it * 2 } // Right(2)
    val result: Either = Left(UnknownUser)
    result.map { it * 2 } // Left(UnknownUser)

    View Slide

  288. Either (flatMap)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Right(2)
    result1.flatMap { one ->
    result2.map { two ->
    one + two
    }
    } // Right(3)

    View Slide

  289. Either (flatMap)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Right(2)
    result1.flatMap { one ->
    result2.map { two ->
    one + two
    }
    } // Right(3)

    View Slide

  290. Either (flatMap)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Right(2)
    result1.flatMap { one ->
    result2.map { two ->
    one + two
    }
    } // Right(3)

    View Slide

  291. Either (flatMap)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Right(2)
    result1.flatMap { one ->
    result2.map { two ->
    one + two
    }
    } // Right(3)

    View Slide

  292. Either (flatMap)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Right(2)
    result1.flatMap { one ->
    result2.map { two ->
    one + two
    }
    } // Right(3)

    View Slide

  293. Either (flatMap)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Right(2)
    result1.flatMap { one ->
    result2.map { two ->
    one + two
    }
    } // Right(3)

    View Slide

  294. Either (flatMap)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Right(2)
    result1.flatMap { one ->
    result2.map { two ->
    one + two
    }
    } // Right(3)

    View Slide

  295. Either (flatMap)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Left(UnknownUser)
    result1.flatMap { one ->
    result2.map { two ->
    one + two
    }
    } // Left(UnknownUser)

    View Slide

  296. Either (flatMap)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Left(UnknownUser)
    result1.flatMap { one ->
    result2.map { two ->
    one + two
    }
    } // Left(UnknownUser)

    View Slide

  297. Either (flatMap)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Left(UnknownUser)
    result1.flatMap { one ->
    result2.map { two ->
    one + two
    }
    } // Left(UnknownUser)

    View Slide

  298. Either (Monad Binding)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Right(2)
    Either.monad.binding {
    val one = result1.bind()
    val two = result2.bind()
    one + two
    }.fix() // Right(3)

    View Slide

  299. Either (Monad Binding)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Right(2)
    Either.monad.binding {
    val one = result1.bind()
    val two = result2.bind()
    one + two
    }.fix() // Right(3)

    View Slide

  300. Either (Monad Binding)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Right(2)
    Either.monad.binding {
    val one = result1.bind()
    val two = result2.bind()
    one + two
    }.fix() // Right(3)

    View Slide

  301. Either (Monad Binding)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Right(2)
    Either.monad.binding {
    val one = result1.bind()
    val two = result2.bind()
    one + two
    }.fix() // Right(3)

    View Slide

  302. Either (Monad Binding)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Right(2)
    Either.monad.binding {
    val one = result1.bind()
    val two = result2.bind()
    one + two
    }.fix() // Right(3)

    View Slide

  303. Either (Monad Binding)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Right(2)
    Either.monad.binding {
    val one = result1.bind()
    val two = result2.bind()
    one + two
    }.fix() // Right(3)

    View Slide

  304. Either (Monad Binding)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Right(2)
    Either.monad.binding {
    val one = result1.bind()
    val two = result2.bind()
    one + two
    }.fix() // Right(3)

    View Slide

  305. Either (Monad Binding)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Right(2)
    Either.monad.binding {
    val one = result1.bind()
    val two = result2.bind()
    one + two
    }.fix() // Right(3)

    View Slide

  306. Either (Monad Binding)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Right(2)
    Either.monad.binding {
    val one = result1.bind()
    val two = result2.bind()
    one + two
    }.fix() // Right(3)

    View Slide

  307. Either (Monad Binding)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Left(UnknownUser)
    Either.monad.binding {
    val one = result1.bind()
    val two = result2.bind()
    one + two
    }.fix() // Left(UnknownUser)

    View Slide

  308. Either (Monad Binding)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Left(UnknownUser)
    Either.monad.binding {
    val one = result1.bind()
    val two = result2.bind()
    one + two
    }.fix() // Left(UnknownUser)

    View Slide

  309. Either (Monad Binding)
    sealed class DomainError { /* ... */ }
    val result1: Either = Right(1)
    val result2: Either = Left(UnknownUser)
    Either.monad.binding {
    val one = result1.bind()
    val two = result2.bind()
    one + two
    }.fix() // Left(UnknownUser)

    View Slide

  310. Either (Applicative Builder)
    sealed class CoffeeMakerError { /* ... */ }
    val espressoResult: Either = Right(Espresso(0.4))
    val waterResult: Either = Right(Water(0.6))
    Either.applicative()
    .map(espressoResult, waterResult) { (espresso, water) ->
    Americano(espresso, water)
    }.fix()
    // Right(Americano(espresso=Espresso(%=0.4), water=Water(%=0.6)))

    View Slide

  311. Either (Applicative Builder)
    sealed class CoffeeMakerError { /* ... */ }
    val espressoResult: Either = Right(Espresso(0.4))
    val waterResult: Either = Right(Water(0.6))
    Either.applicative()
    .map(espressoResult, waterResult) { (espresso, water) ->
    Americano(espresso, water)
    }.fix()
    // Right(Americano(espresso=Espresso(%=0.4), water=Water(%=0.6)))

    View Slide

  312. Either (Applicative Builder)
    sealed class CoffeeMakerError { /* ... */ }
    val espressoResult: Either = Right(Espresso(0.4))
    val waterResult: Either = Right(Water(0.6))
    Either.applicative()
    .map(espressoResult, waterResult) { (espresso, water) ->
    Americano(espresso, water)
    }.fix()
    // Right(Americano(espresso=Espresso(%=0.4), water=Water(%=0.6)))

    View Slide

  313. Either (Applicative Builder)
    sealed class CoffeeMakerError { /* ... */ }
    val espressoResult: Either = Right(Espresso(0.4))
    val waterResult: Either = Right(Water(0.6))
    Either.applicative()
    .map(espressoResult, waterResult) { (espresso, water) ->
    Americano(espresso, water)
    }.fix()
    // Right(Americano(espresso=Espresso(%=0.4), water=Water(%=0.6)))

    View Slide

  314. Either (Applicative Builder)
    sealed class CoffeeMakerError { /* ... */ }
    val espressoResult: Either = Right(Espresso(0.4))
    val waterResult: Either = Right(Water(0.6))
    Either.applicative()
    .map(espressoResult, waterResult) { (espresso, water) ->
    Americano(espresso, water)
    }.fix()
    // Right(Americano(espresso=Espresso(%=0.4), water=Water(%=0.6)))

    View Slide

  315. Either (Applicative Builder)
    sealed class CoffeeMakerError { /* ... */ }
    val espressoResult: Either = Right(Espresso(0.4))
    val waterResult: Either = Right(Water(0.6))
    Either.applicative()
    .map(espressoResult, waterResult) { (espresso, water) ->
    Americano(espresso, water)
    }.fix()
    // Right(Americano(espresso=Espresso(%=0.4), water=Water(%=0.6)))

    View Slide

  316. Either (Applicative Builder)
    sealed class CoffeeMakerError { /* ... */ }
    val espressoResult: Either = Right(Espresso(0.4))
    val waterResult: Either = Right(Water(0.6))
    Either.applicative()
    .map(espressoResult, waterResult) { (espresso, water) ->
    Americano(espresso, water)
    }.fix()
    // Right(Americano(espresso=Espresso(%=0.4), water=Water(%=0.6)))

    View Slide

  317. Either (Applicative Builder)
    sealed class CoffeeMakerError { /* ... */ }
    val espressoResult: Either = Right(Espresso(0.4))
    val waterResult: Either = Right(Water(0.6))
    Either.applicative()
    .map(espressoResult, waterResult) { (espresso, water) ->
    Americano(espresso, water)
    }.fix()
    // Right(Americano(espresso=Espresso(%=0.4), water=Water(%=0.6)))

    View Slide

  318. Either (Applicative Builder)
    sealed class CoffeeMakerError { /* ... */ }
    val espressoResult: Either = Right(Espresso(0.4))
    val waterResult: Either = Right(Water(0.6))
    Either.applicative()
    .map(espressoResult, waterResult) { (espresso, water) ->
    Americano(espresso, water)
    }.fix()
    // Right(Americano(espresso=Espresso(%=0.4), water=Water(%=0.6)))

    View Slide

  319. Either (Applicative Builder)
    sealed class CoffeeMakerError { /* ... */ }
    val espressoResult: Either = Right(Espresso(0.4))
    val waterResult: Either = Right(Water(0.6))
    Either.applicative()
    .map(espressoResult, waterResult) { (espresso, water) ->
    Americano(espresso, water)
    }.fix()
    // Right(Americano(espresso=Espresso(%=0.4), water=Water(%=0.6)))

    View Slide

  320. Either (Applicative Builder)
    sealed class CoffeeMakerError { /* ... */ }
    val espressoResult: Either = Right(Espresso(0.4))
    val waterResult: Either = Right(Water(0.6))
    Either.applicative()
    .map(espressoResult, waterResult) { (espresso, water) ->
    Americano(espresso, water)
    }.fix()
    // Right(Americano(espresso=Espresso(%=0.4), water=Water(%=0.6)))

    View Slide

  321. Either (Applicative Builder)
    sealed class CoffeeMakerError { /* ... */ }
    val espressoResult: Either = Right(Espresso(0.4))
    val waterResult: Either = Left(RefillWater)
    Either.applicative()
    .map(espressoResult, waterResult) { (espresso, water) ->
    Americano(espresso, water)
    }.fix()
    // Left(RefillWater)

    View Slide

  322. Either (Applicative Builder)
    sealed class CoffeeMakerError { /* ... */ }
    val espressoResult: Either = Right(Espresso(0.4))
    val waterResult: Either = Left(RefillWater)
    Either.applicative()
    .map(espressoResult, waterResult) { (espresso, water) ->
    Americano(espresso, water)
    }.fix()
    // Left(RefillWater)

    View Slide

  323. Either (Applicative Builder)
    sealed class CoffeeMakerError { /* ... */ }
    val espressoResult: Either = Right(Espresso(0.4))
    val waterResult: Either = Left(RefillWater)
    Either.applicative()
    .map(espressoResult, waterResult) { (espresso, water) ->
    Americano(espresso, water)
    }.fix()
    // Left(RefillWater)

    View Slide

  324. More…
    • Try // Success - Failure
    • Validated // Valid - Invalid
    • Eval // Now - Always - Later - Defer
    • TupleN // Tuple2 - Tuple22

    View Slide

  325. Typeclasses
    compile “io.arrow-kt:arrow-typeclasses:$arrow_version”
    kapt “io.arrow-kt:arrow-meta:$arrow_version”

    View Slide

  326. Typeclasses
    • Polymorphism in functional programming.

    • Separates data from behaviour.

    • Maybe governed by algebraic / category theoretic laws.

    • Implemented as interfaces in Kotlin.

    • One Typeclass instance per type.

    View Slide

  327. Typeclasses
    • Show
    • Eq
    • Semigroup
    • Functor
    • Monad
    • …

    View Slide

  328. Show
    interface Show {
    fun A.show(): String
    }
    The Show typeclass abstracts the ability to obtain a String representation of any object.

    View Slide

  329. Show
    interface Show {
    fun A.show(): String
    }
    The Show typeclass abstracts the ability to obtain a String representation of any object.

    View Slide

  330. Show
    interface Show {
    fun A.show(): String
    }
    The Show typeclass abstracts the ability to obtain a String representation of any object.

    View Slide

  331. Show
    interface Show {
    fun A.show(): String
    }
    The Show typeclass abstracts the ability to obtain a String representation of any object.

    View Slide

  332. Eq
    interface Eq {
    fun F.eqv(b: F): Boolean
    fun F.neqv(b: F): Boolean = !eqv(b)
    }
    The Eq typeclass abstracts the ability to compare two instances of any object. It can be
    compared to the typeclass equivalent of Java’s Object#equals.

    View Slide

  333. Eq
    interface Eq {
    fun F.eqv(b: F): Boolean
    fun F.neqv(b: F): Boolean = !eqv(b)
    }
    The Eq typeclass abstracts the ability to compare two instances of any object. It can be
    compared to the typeclass equivalent of Java’s Object#equals.

    View Slide

  334. Eq
    interface Eq {
    fun F.eqv(b: F): Boolean
    fun F.neqv(b: F): Boolean = !eqv(b)
    }
    The Eq typeclass abstracts the ability to compare two instances of any object. It can be
    compared to the typeclass equivalent of Java’s Object#equals.

    View Slide

  335. Eq
    interface Eq {
    fun F.eqv(b: F): Boolean
    fun F.neqv(b: F): Boolean = !eqv(b)
    }
    The Eq typeclass abstracts the ability to compare two instances of any object. It can be
    compared to the typeclass equivalent of Java’s Object#equals.

    View Slide

  336. Eq
    interface Eq {
    fun F.eqv(b: F): Boolean
    fun F.neqv(b: F): Boolean = !eqv(b)
    }
    The Eq typeclass abstracts the ability to compare two instances of any object. It can be
    compared to the typeclass equivalent of Java’s Object#equals.

    View Slide

  337. Semigroup
    interface Semigroup {
    fun A.combine(b: A): A
    operator fun A.plus(b: A): A = this.combine(b)
    }
    The Semigroup for some given type A has a single operation combine which takes two
    values of type A, and returns a value of type A. This operation must be associative.

    View Slide

  338. Semigroup
    interface Semigroup {
    fun A.combine(b: A): A
    operator fun A.plus(b: A): A = this.combine(b)
    }
    The Semigroup for some given type A has a single operation combine which takes two
    values of type A, and returns a value of type A. This operation must be associative.

    View Slide

  339. Semigroup
    interface Semigroup {
    fun A.combine(b: A): A
    operator fun A.plus(b: A): A = this.combine(b)
    }
    The Semigroup for some given type A has a single operation combine which takes two
    values of type A, and returns a value of type A. This operation must be associative.

    View Slide

  340. Semigroup
    interface Semigroup {
    fun A.combine(b: A): A
    operator fun A.plus(b: A): A = this.combine(b)
    }
    The Semigroup for some given type A has a single operation combine which takes two
    values of type A, and returns a value of type A. This operation must be associative.

    View Slide

  341. Semigroup
    interface Semigroup {
    fun A.combine(b: A): A
    operator fun A.plus(b: A): A = this.combine(b)
    }
    The Semigroup for some given type A has a single operation combine which takes two
    values of type A, and returns a value of type A. This operation must be associative.

    View Slide

  342. Creating Instances
    data class Person(val firstName: String, val lastName: String) {
    companion object
    }
    @extension interface PersonShow : Show {
    override fun Person.show(): String = "$firstName $lastName"
    }
    val john = Person("John", "Doe")
    Person.show().run {
    john.show()
    } // John Doe

    View Slide

  343. Creating Instances
    data class Person(val firstName: String, val lastName: String) {
    companion object
    }
    @extension interface PersonShow : Show {
    override fun Person.show(): String = "$firstName $lastName"
    }
    val john = Person("John", "Doe")
    Person.show().run {
    john.show()
    } // John Doe

    View Slide

  344. Creating Instances
    data class Person(val firstName: String, val lastName: String) {
    companion object
    }
    @extension interface PersonShow : Show {
    override fun Person.show(): String = "$firstName $lastName"
    }
    val john = Person("John", "Doe")
    Person.show().run {
    john.show()
    } // John Doe

    View Slide

  345. Creating Instances
    data class Person(val firstName: String, val lastName: String) {
    companion object
    }
    @extension interface PersonShow : Show {
    override fun Person.show(): String = "$firstName $lastName"
    }
    val john = Person("John", "Doe")
    Person.show().run {
    john.show()
    } // John Doe

    View Slide

  346. Creating Instances
    data class Person(val firstName: String, val lastName: String) {
    companion object
    }
    @extension interface PersonShow : Show {
    override fun Person.show(): String = "$firstName $lastName"
    }
    val john = Person("John", "Doe")
    Person.show().run {
    john.show()
    } // John Doe

    View Slide

  347. Creating Instances
    data class Person(val firstName: String, val lastName: String) {
    companion object
    }
    @extension interface PersonShow : Show {
    override fun Person.show(): String = "$firstName $lastName"
    }
    val john = Person("John", "Doe")
    Person.show().run {
    john.show()
    } // John Doe

    View Slide

  348. Creating Instances
    data class Person(val firstName: String, val lastName: String) {
    companion object
    }
    @extension interface PersonShow : Show {
    override fun Person.show(): String = "$firstName $lastName"
    }
    val john = Person("John", "Doe")
    Person.show().run {
    john.show()
    } // John Doe

    View Slide

  349. Creating Instances
    data class Person(val firstName: String, val lastName: String) {
    companion object
    }
    @extension interface PersonShow : Show {
    override fun Person.show(): String = "$firstName $lastName"
    }
    val john = Person("John", "Doe")
    Person.show().run {
    john.show()
    } // John Doe

    View Slide

  350. Creating Instances
    data class Person(val firstName: String, val lastName: String) {
    companion object
    }
    @extension interface PersonShow : Show {
    override fun Person.show(): String = "$firstName $lastName"
    }
    val john = Person("John", "Doe")
    Person.show().run {
    john.show()
    } // John Doe

    View Slide

  351. Creating Instances
    data class Person(val firstName: String, val lastName: String) {
    companion object
    }
    @extension interface PersonShow : Show {
    override fun Person.show(): String = "$firstName $lastName"
    }
    val john = Person("John", "Doe")
    Person.show().run {
    john.show()
    } // John Doe

    View Slide

  352. Creating Instances
    data class Person(val firstName: String, val lastName: String) {
    companion object
    }
    @extension interface PersonShow : Show {
    override fun Person.show(): String = "$firstName $lastName"
    }
    val john = Person("John", "Doe")
    Person.show().run {
    john.show()
    } // John Doe

    View Slide

  353. Creating Instances
    data class Person(val firstName: String, val lastName: String) {
    companion object
    }
    @extension interface PersonShow : Show {
    override fun Person.show(): String = "$firstName $lastName"
    }
    val john = Person("John", "Doe")
    Person.show().run {
    john.show()
    } // John Doe

    View Slide

  354. More…
    • Hash
    • Order
    • Traverse
    • Applicative
    • And many more…

    View Slide

  355. Optics
    compile “io.arrow-kt:arrow-optics:$arrow_version”
    kapt “io.arrow-kt:arrow-meta:$arrow_version”

    View Slide

  356. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  357. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  358. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  359. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  360. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  361. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  362. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  363. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  364. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  365. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  366. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  367. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  368. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  369. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  370. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  371. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  372. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  373. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  374. Lens
    @optics data class UserProfile(
    val name: Name, /* Not shown for brevity */
    val contact: Contact
    ) { companion object }
    @optics data class Contact(
    val email: String,
    val phone: String
    ) { companion object }

    View Slide

  375. Without Lens
    val profile = UserProfile(
    Name("John", "Doe"),
    Contact("[email protected]", "6483920164")
    )
    val updatedProfile = profile.copy(
    contact = profile.contact.copy(
    email = "[email protected]"
    )
    )

    View Slide

  376. Without Lens
    val profile = UserProfile(
    Name("John", "Doe"),
    Contact("[email protected]", "6483920164")
    )
    val updatedProfile = profile.copy(
    contact = profile.contact.copy(
    email = "[email protected]"
    )
    )

    View Slide

  377. Without Lens
    val profile = UserProfile(
    Name("John", "Doe"),
    Contact("[email protected]", "6483920164")
    )
    val updatedProfile = profile.copy(
    contact = profile.contact.copy(
    email = "[email protected]"
    )
    )

    View Slide

  378. Without Lens
    val profile = UserProfile(
    Name("John", "Doe"),
    Contact("[email protected]", "6483920164")
    )
    val updatedProfile = profile.copy(
    contact = profile.contact.copy(
    email = "[email protected]"
    )
    )

    View Slide

  379. Without Lens
    val profile = UserProfile(
    Name("John", "Doe"),
    Contact("[email protected]", "6483920164")
    )
    val updatedProfile = profile.copy(
    contact = profile.contact.copy(
    email = "[email protected]"
    )
    )

    View Slide

  380. Without Lens
    val profile = UserProfile(
    Name("John", "Doe"),
    Contact("[email protected]", "6483920164")
    )
    val updatedProfile = profile.copy(
    contact = profile.contact.copy(
    email = "[email protected]"
    )
    )

    View Slide

  381. With Lens
    val profile = UserProfile( /* … */ )
    val emailLens: Lens = UserProfile.contact.email
    val workEmail = "[email protected]"
    val updatedProfile = emailLens.modify(profile) { workEmail }
    val email = emailLens.get(profile)

    View Slide

  382. With Lens
    val profile = UserProfile( /* … */ )
    val emailLens: Lens = UserProfile.contact.email
    val workEmail = "[email protected]"
    val updatedProfile = emailLens.modify(profile) { workEmail }
    val email = emailLens.get(profile)

    View Slide

  383. With Lens
    val profile = UserProfile( /* … */ )
    val emailLens: Lens = UserProfile.contact.email
    val workEmail = "[email protected]"
    val updatedProfile = emailLens.modify(profile) { workEmail }
    val email = emailLens.get(profile)

    View Slide

  384. With Lens
    val profile = UserProfile( /* … */ )
    val emailLens: Lens = UserProfile.contact.email
    val workEmail = "[email protected]"
    val updatedProfile = emailLens.modify(profile) { workEmail }
    val email = emailLens.get(profile)

    View Slide

  385. With Lens
    val profile = UserProfile( /* … */ )
    val emailLens: Lens = UserProfile.contact.email
    val workEmail = "[email protected]"
    val updatedProfile = emailLens.modify(profile) { workEmail }
    val email = emailLens.get(profile)

    View Slide

  386. With Lens
    val profile = UserProfile( /* … */ )
    val emailLens: Lens = UserProfile.contact.email
    val workEmail = "[email protected]"
    val updatedProfile = emailLens.modify(profile) { workEmail }
    val email = emailLens.get(profile)

    View Slide

  387. With Lens
    val profile = UserProfile( /* … */ )
    val emailLens: Lens = UserProfile.contact.email
    val workEmail = "[email protected]"
    val updatedProfile = emailLens.modify(profile) { workEmail }
    val email = emailLens.get(profile)

    View Slide

  388. With Lens
    val profile = UserProfile( /* … */ )
    val emailLens: Lens = UserProfile.contact.email
    val workEmail = "[email protected]"
    val updatedProfile = emailLens.modify(profile) { workEmail }
    val email = emailLens.get(profile)

    View Slide

  389. With Lens
    val profile = UserProfile( /* … */ )
    val emailLens: Lens = UserProfile.contact.email
    val workEmail = "[email protected]"
    val updatedProfile = emailLens.modify(profile) { workEmail }
    val email = emailLens.get(profile)

    View Slide

  390. With Lens
    val profile = UserProfile( /* … */ )
    val emailLens: Lens = UserProfile.contact.email
    val workEmail = "[email protected]"
    val updatedProfile = emailLens.modify(profile) { workEmail }
    val email = emailLens.get(profile)

    View Slide

  391. With Lens
    val profile = UserProfile( /* … */ )
    val emailLens: Lens = UserProfile.contact.email
    val workEmail = "[email protected]"
    val updatedProfile = emailLens.modify(profile) { workEmail }
    val email = emailLens.get(profile)

    View Slide

  392. With Lens
    val profile = UserProfile( /* … */ )
    val emailLens: Lens = UserProfile.contact.email
    val workEmail = "[email protected]"
    val updatedProfile = emailLens.modify(profile) { workEmail }
    val email = emailLens.get(profile)

    View Slide

  393. With Lens
    val profile = UserProfile( /* … */ )
    val emailLens: Lens = UserProfile.contact.email
    val workEmail = "[email protected]"
    val updatedProfile = emailLens.modify(profile) { workEmail }
    val email = emailLens.get(profile)

    View Slide

  394. With Lens
    val profile = UserProfile( /* … */ )
    val emailLens: Lens = UserProfile.contact.email
    val workEmail = "[email protected]"
    val updatedProfile = emailLens.modify(profile) { workEmail }
    val email = emailLens.get(profile)

    View Slide

  395. With Lens
    val profile = UserProfile( /* … */ )
    val emailLens: Lens = UserProfile.contact.email
    val workEmail = "[email protected]"
    val updatedProfile = emailLens.modify(profile) { workEmail }
    val email = emailLens.get(profile)

    View Slide

  396. With Lens
    val profile = UserProfile( /* … */ )
    val emailLens: Lens = UserProfile.contact.email
    val workEmail = "[email protected]"
    val updatedProfile = emailLens.modify(profile) { workEmail }
    val email = emailLens.get(profile) // “[email protected]

    View Slide

  397. With Lens
    val profile = UserProfile( /* … */ )
    val emailLens: Lens = UserProfile.contact.email
    val workEmail = "[email protected]"
    val updatedProfile = emailLens.modify(profile) { workEmail }
    val email = emailLens.get(profile)

    View Slide

  398. Optional
    @optics data class ShoppingCart(
    val id: String,
    val cartItems: ListK
    ) { companion object }
    @optics data class CartItem(
    val product: Product, /* Not shown for brevity */
    val quantity: Int
    ) { companion object }

    View Slide

  399. Optional
    @optics data class ShoppingCart(
    val id: String,
    val cartItems: ListK
    ) { companion object }
    @optics data class CartItem(
    val product: Product, /* Not shown for brevity */
    val quantity: Int
    ) { companion object }

    View Slide

  400. Optional
    @optics data class ShoppingCart(
    val id: String,
    val cartItems: ListK
    ) { companion object }
    @optics data class CartItem(
    val product: Product, /* Not shown for brevity */
    val quantity: Int
    ) { companion object }

    View Slide

  401. Optional
    @optics data class ShoppingCart(
    val id: String,
    val cartItems: ListK
    ) { companion object }
    @optics data class CartItem(
    val product: Product, /* Not shown for brevity */
    val quantity: Int
    ) { companion object }

    View Slide

  402. Optional
    @optics data class ShoppingCart(
    val id: String,
    val cartItems: ListK
    ) { companion object }
    @optics data class CartItem(
    val product: Product, /* Not shown for brevity */
    val quantity: Int
    ) { companion object }

    View Slide

  403. Optional
    @optics data class ShoppingCart(
    val id: String,
    val cartItems: ListK
    ) { companion object }
    @optics data class CartItem(
    val product: Product, /* Not shown for brevity */
    val quantity: Int
    ) { companion object }

    View Slide

  404. Optional
    @optics data class ShoppingCart(
    val id: String,
    val cartItems: ListK
    ) { companion object }
    @optics data class CartItem(
    val product: Product, /* Not shown for brevity */
    val quantity: Int
    ) { companion object }

    View Slide

  405. Optional (Set)
    val shoppingCart = ShoppingCart("CRT19321", cartItems)
    val quantityOptional: Optional = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .quantity
    val updatedCart = quantityOptional.modify(shoppingCart) { it + 1 }

    View Slide

  406. Optional (Set)
    val shoppingCart = ShoppingCart("CRT19321", cartItems)
    val quantityOptional: Optional = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .quantity
    val updatedCart = quantityOptional.modify(shoppingCart) { it + 1 }

    View Slide

  407. Optional (Set)
    val shoppingCart = ShoppingCart("CRT19321", cartItems)
    val quantityOptional: Optional = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .quantity
    val updatedCart = quantityOptional.modify(shoppingCart) { it + 1 }

    View Slide

  408. Optional (Set)
    val shoppingCart = ShoppingCart("CRT19321", cartItems)
    val quantityOptional: Optional = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .quantity
    val updatedCart = quantityOptional.modify(shoppingCart) { it + 1 }

    View Slide

  409. Optional (Set)
    val shoppingCart = ShoppingCart("CRT19321", cartItems)
    val quantityOptional: Optional = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .quantity
    val updatedCart = quantityOptional.modify(shoppingCart) { it + 1 }

    View Slide

  410. Optional (Set)
    val shoppingCart = ShoppingCart("CRT19321", cartItems)
    val quantityOptional: Optional = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .quantity
    val updatedCart = quantityOptional.modify(shoppingCart) { it + 1 }

    View Slide

  411. Optional (Set)
    val shoppingCart = ShoppingCart("CRT19321", cartItems)
    val quantityOptional: Optional = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .quantity
    val updatedCart = quantityOptional.modify(shoppingCart) { it + 1 }

    View Slide

  412. Optional (Set)
    val shoppingCart = ShoppingCart("CRT19321", cartItems)
    val quantityOptional: Optional = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .quantity
    val updatedCart = quantityOptional.modify(shoppingCart) { it + 1 }

    View Slide

  413. Optional (Set)
    val shoppingCart = ShoppingCart("CRT19321", cartItems)
    val quantityOptional: Optional = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .quantity
    val updatedCart = quantityOptional.modify(shoppingCart) { it + 1 }

    View Slide

  414. Optional (Set)
    val shoppingCart = ShoppingCart("CRT19321", cartItems)
    val quantityOptional: Optional = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .quantity
    val updatedCart = quantityOptional.modify(shoppingCart) { it + 1 }

    View Slide

  415. Optional (Set)
    val shoppingCart = ShoppingCart("CRT19321", cartItems)
    val quantityOptional: Optional = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .quantity
    val updatedCart = quantityOptional.modify(shoppingCart) { it + 1 }

    View Slide

  416. Optional (Set)
    val shoppingCart = ShoppingCart("CRT19321", cartItems)
    val quantityOptional: Optional = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .quantity
    val updatedCart = quantityOptional.modify(shoppingCart) { it + 1 }

    View Slide

  417. Optional (Set)
    val shoppingCart = ShoppingCart("CRT19321", cartItems)
    val quantityOptional: Optional = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .quantity
    val updatedCart = quantityOptional.modify(shoppingCart) { it + 1 }

    View Slide

  418. Optional (Get)
    val cartItemOption = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .getOption(shoppingCart)
    val sameCartItemOption = ListK.index().run {
    ShoppingCart.cartItems[productIndex].getOption(shoppingCart)
    }

    View Slide

  419. Optional (Get)
    val cartItemOption = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .getOption(shoppingCart)
    val sameCartItemOption = ListK.index().run {
    ShoppingCart.cartItems[productIndex].getOption(shoppingCart)
    }

    View Slide

  420. Optional (Get)
    val cartItemOption = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .getOption(shoppingCart)
    val sameCartItemOption = ListK.index().run {
    ShoppingCart.cartItems[productIndex].getOption(shoppingCart)
    }

    View Slide

  421. Optional (Get)
    val cartItemOption = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .getOption(shoppingCart)
    val sameCartItemOption = ListK.index().run {
    ShoppingCart.cartItems[productIndex].getOption(shoppingCart)
    }

    View Slide

  422. Optional (Get)
    val cartItemOption = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .getOption(shoppingCart)
    val sameCartItemOption = ListK.index().run {
    ShoppingCart.cartItems[productIndex].getOption(shoppingCart)
    }

    View Slide

  423. Optional (Get)
    val cartItemOption = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .getOption(shoppingCart)
    val sameCartItemOption = ListK.index().run {
    ShoppingCart.cartItems[productIndex].getOption(shoppingCart)
    }

    View Slide

  424. Optional (Get)
    val cartItemOption = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .getOption(shoppingCart)
    val sameCartItemOption = ListK.index().run {
    ShoppingCart.cartItems[productIndex].getOption(shoppingCart)
    }

    View Slide

  425. Optional (Get)
    val cartItemOption = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .getOption(shoppingCart)
    val sameCartItemOption = ListK.index().run {
    ShoppingCart.cartItems[productIndex].getOption(shoppingCart)
    }

    View Slide

  426. Optional (Get)
    val cartItemOption = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .getOption(shoppingCart)
    val sameCartItemOption = ListK.index().run {
    ShoppingCart.cartItems[productIndex].getOption(shoppingCart)
    }

    View Slide

  427. Optional (Get)
    val cartItemOption = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .getOption(shoppingCart)
    val sameCartItemOption = ListK.index().run {
    ShoppingCart.cartItems[productIndex].getOption(shoppingCart)
    }

    View Slide

  428. Optional (Get)
    val cartItemOption = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .getOption(shoppingCart)
    val sameCartItemOption = ListK.index().run {
    ShoppingCart.cartItems[productIndex].getOption(shoppingCart)
    }

    View Slide

  429. Optional (Get)
    val cartItemOption = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .getOption(shoppingCart)
    val sameCartItemOption = ListK.index().run {
    ShoppingCart.cartItems[productIndex].getOption(shoppingCart)
    }

    View Slide

  430. Optional (Get)
    val cartItemOption = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .getOption(shoppingCart)
    val sameCartItemOption = ListK.index().run {
    ShoppingCart.cartItems[productIndex].getOption(shoppingCart)
    }

    View Slide

  431. Optional (Get)
    val cartItemOption = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .getOption(shoppingCart)
    val sameCartItemOption = ListK.index().run {
    ShoppingCart.cartItems[productIndex].getOption(shoppingCart)
    }

    View Slide

  432. Optional (Get)
    val cartItemOption = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .getOption(shoppingCart)
    val sameCartItemOption = ListK.index().run {
    ShoppingCart.cartItems[productIndex].getOption(shoppingCart)
    }

    View Slide

  433. Optional (Get)
    val cartItemOption = ShoppingCart
    .cartItems
    .index(ListK.index(), productIndex)
    .getOption(shoppingCart)
    val sameCartItemOption = ListK.index().run {
    ShoppingCart.cartItems[productIndex].getOption(shoppingCart)
    }

    View Slide

  434. More…
    • Iso
    • Prism
    • Getter / Setter
    • Fold
    • Each
    • And others …

    View Slide

  435. That’s not it…
    • Arrow Fx

    • Effects

    • Arrow Query Language

    • Generic

    • Integrations

    • Free

    • Recursion Schemes

    View Slide

  436. Resources
    • https://arrow-kt.io/docs/

    • http://learnyouahaskell.com/

    • https://caster.io/courses/functional-programming-in-kotlin-with-arrow

    • https://github.com/hemanth/functional-programming-jargon#function

    • https://wiki.haskell.org/Typeclassopedia

    • http://nealford.com/functionalthinking.html

    • https://prod.packtpub.com/in/application-development/functional-kotlin

    View Slide

  437. end;
    @ragunathjawahar
    Twitter / Medium / GitHub

    View Slide