Functional Programming with Arrow

B3f560d34c14a9113e5024bc34ac26a0?s=47 Mohit S
January 24, 2018

Functional Programming with Arrow

Discussion of data types and type classes available in the library called Arrow for Kotlin.

B3f560d34c14a9113e5024bc34ac26a0?s=128

Mohit S

January 24, 2018
Tweet

Transcript

  1. 2.
  2. 3.
  3. 4.

    Functional Programming with Λrrow • Data Types • Optics •

    Error Handling • Type Classes • Types of Polymorphism • Ad-hoc Polymorphism • Type classes proposal for Kotlin
  4. 7.

    data class Point2D data class Cords (val x: Int, val

    y: Int) Isomorphism (val x: Int, val y: Int)
  5. 8.

    data class Point2D data class Cords (val x: Int, val

    y: Int) Isomorphism (val x: Int, val y: Int)
  6. 9.

    data class Point2D data class Cords (val x: Int, val

    y: Int) Isomorphism (val x: Int, val y: Int) fun point2DToCords (point2D: Point2D): Cords { return Cords(point2D.x, point2D.y) }
  7. 10.

    data class Point2D data class Cords (val x: Int, val

    y: Int) Isomorphism (val x: Int, val y: Int) fun cordsToPoint2D (cord: Cord): Point2D { return Point2D(cord.x, cord.y) }
  8. 12.

    Isomorphism Source: Focus: f ≇ g = IdA g ≇

    f = IdS f: "-> g: "-> S A S A A S
  9. 13.

    Isomorphism interface Iso<S, T, A, B> { /** * Get

    the focus of a [Iso] "*/ fun get(s: S): A /** * Get the modified focus of a [Iso] "*/ fun reverseGet(b: B): T }
  10. 14.

    Isomorphism val pointIsoCords : Iso<Point2D, Cords> = Iso( get =

    { point !-> Cords(point.x, point.y) }, reverseGet = { cords !-> Point2D(cords.x, cords.y) } )
  11. 15.

    Isomorphism val point = Point2D(6, 10) val cords: Cords =

    pointIsoCords.get(point) "// Cords(6, 10)
  12. 16.

    Isomorphism val cords = Cords(6, 10) val point2D: Point2D =

    pointIsoCords.reverseGet(cords) "// Point2D(6, 10)
  13. 17.

    data class Point2D data class Tuple2 (val x: Int, val

    y: Int) Isomorphism (val x: Int, val y: Int)
  14. 18.

    data class Tuple2<out A, out B>(val a: A, val b:

    B) Isomorphism data class Tuple3<out A, out B, out C>(val a: A, val b: B, val c: C) data class Tuple4<out A, out B, out C, out D>("..)
  15. 19.

    val pointIsoTuple: Iso<Point2D, Tuple2<Int, Int">> = Iso( get = {

    point !-> point.x toT point.y }, reverseGet = { tuple !-> Point2D(tuple.a, tuple.b) } ) Isomorphism
  16. 20.

    var point2D = Point2D(1, 2) val tuple2 = pointIsoTuple.get(point2D) "//

    Tuple2(a=1, b=2) val point2D = pointIsoTuple.reverseGet(tuple2) "// Point2D(x=1, y=2) Isomorphism
  17. 21.

    val pointIsoTuple = Iso( get = { point !-> Tuple2(point.x,

    point.y) }, reverseGet = { tuple !-> Point2D(tuple.a, tuple.b) } ) Generating Isomorphism data class Point2D (val x: Int, val y: Int)
  18. 25.

    Lens Source: S Purpose: Set, Get, Copy an immutable data

    structure through functional references.
  19. 28.

    Lens data class Person(val name: String, val age: Int) val

    personNameLens : Lens<Person, String> = Lens( get = { person !-> person.name }, set = { newName !-> {foo !-> foo.copy(name = newName)} } )
  20. 29.

    Lens val person = Person("John Doe", 100) val personNameLens :

    Lens<Person, String> = Lens( get = { person !-> person.name }, set = { newName !-> {foo !-> foo.copy(name = newName)} } )
  21. 30.

    Lens val person = Person("John Doe", 100) val newPerson =

    personNameLens.set(person, "John Doe Jr”) // Person(name=John Doe Jr, age=100)
  22. 31.

    Lens data class Employee(val name: String, val company: Company) data

    class Company(val name: String, val address: Address) data class Address(val city: String, val street: Street) data class Street(val number: Int, val name: String)
  23. 32.

    Lens val street = Street(1, "hacker Way”) val address =

    Address("Menlo Park, CA", street) val company = Company("Facebook", address) val employee = Employee("John Doe", company)
  24. 33.

    Lens employee.copy( company = employee.company.copy( address = employee.company.address.copy( street =

    employee.company.address.street.copy( name = employee.company.address.street.name.capitalize() ) ) ) )
  25. 34.

    Lens data class Street(val number: Int, val name: String) data

    class Employee(val name: String, val company: Company)
  26. 35.

    val company: Company) Lens data class Employee(val name: String, val

    company: Company) val employeeCompany: Lens<Employee, Company> = Lens(get = { it.company }, set = { company !-> { employee !-> employee.copy(company = company) } } )
  27. 36.

    data class Company(val name: String, val address: Address) Lens val

    companyAddress: Lens<Company, Address> = Lens( get = { it.address }, set = { address !-> { company !-> company.copy(address = address) } }) val address: Address)
  28. 37.

    data class Address(val city: String, val street: Street) Lens val

    addressStreet: Lens<Address, Street> = Lens( get = { it.street }, set = { street !-> { address !-> address.copy(street = street) } }) val street: Street)
  29. 38.

    data class Street(val number: Int, val name: String) Lens val

    streetName: Lens<Street, String> = Lens( get = { it.name }, set = { name !-> { street !-> street.copy(name = name) } } ) val name: String)
  30. 39.

    Lens val employeeStreetName = employeeCompany compose companyAddress compose addressStreet compose

    streetName val employee = employeeStreetName.modify( employee, String"::capitalize) // Employee(name=John Doe, ... name=Hacker Way))))
  31. 40.

    val company: Company) Generating Lenses val employeeCompany: Lens<Employee, Company> =

    Lens(get = { it.company }, set = { company !-> { employee !-> employee.copy(company = company) } } ) data class Employee(val name: String, val company: Company)
  32. 46.

    val books : List<Book>? = getBooks() books"?.map { ""... }

    books"?.flatMap { ""... } books"?.fold(""...)
  33. 48.

    val book : Book? = getBookForId(1000) book"?.map { ""... }

    book"?.flatMap { ""... } book"?.fold(""...)
  34. 50.

    sealed class Option<out A> { object None : Option<Nothing>() data

    class Some<out T>(val t: T) : Option<T>() }
  35. 51.

    val option : Option<Book> = getBookForId(1000) fun getBookForId(id : Int)

    : Option<Book> { val book : Book? = getAllBooksFromDB().find { it.id "== id } return if (book "!= null) { Some(book) } else { None } }
  36. 52.

    val option : Option<Book> = getBookForId(1000) fun getBookForId(id : Int)

    : Option<Book> { val book : Book? = getAllBooksFromDB().find { it.id "== id } } return if (book "!= null) { Some(book) } else { None }
  37. 53.
  38. 54.

    val option : Option<Book> = getBookForId(1000) fun getBookForId(id : Int)

    : Option<Book> { return getAllBooksFromDB() .find { it.id "== id } .toOption() }
  39. 56.

    val option : Option<Book> = getBookForId(1000) val description = option.fold(

    ifEmpty = { "No Description" }, some = { it.description } )
  40. 58.

    fun reciprocal(i: Int): Double { if (i "== 0) throw

    IllegalArgumentException("Can’t be 0") return 1.0 / i }
  41. 60.

    try { val reciprocal = reciprocal(2) compute(reciprocal) } catch (e:

    IllegalArgumentException) { log("Failed to take reciprocal”) }
  42. 62.

    sealed class Either<out A, out B> { data class Left<out

    A, out B>(val a: A) : Either<A, B>() data class Right<out A, out B>(val b: B) : Either<A, B>() }
  43. 63.

    fun reciprocal(i: Int): Double { if (i == 0) throw

    IllegalArgumentException(“Can’t be 0") return 1.0 / i }
  44. 64.
  45. 65.

    fun reciprocal(i: Int): { return if (i == 0) {

    } else { 1.0 / i } } Either.left(IllegalArgumentException(“Can’t be 0") Either<Throwable, Double>
  46. 66.

    fun reciprocal(i: Int): { return if (i == 0) {

    } else { } } Either.left(IllegalArgumentException(“Can’t be 0") Either<Throwable, Double> Either.right(1.0 / i)
  47. 67.

    fun reciprocal(i: Int): { return if (i == 0) {

    } else { } } Either.left(IllegalArgumentException(“Can’t be 0") Either<Throwable, Double> Either.right(1.0 / i)
  48. 69.

    val either: Either<Throwable, Double> = reciprocal(2) when(either) { is Either.Left

    "-> log("Failed to take reciprocal") is Either.Right "-> compute(either.b) }
  49. 71.

    fun reciprocal(i: Int): Double { if (i == 0) throw

    IllegalArgumentException(“Can’t be 0") return 1.0 / i } External Library
  50. 72.

    var reciprocal : Double = try { reciprocal(0) } catch

    (e: IllegalArgumentException) { 1.0 }
  51. 74.

    Try { reciprocal(0) }.fold( { t: Throwable !-> log("Failed to

    take reciprocal", t) }, { num: Double !-> compute(num) })
  52. 75.

    sealed class Try<out A> { data class Failure<out A>(val e:

    Throwable) : Try<A>() data class Success<out A>(val value: A) : Try<A>() }
  53. 79.

    Parametric Polymorphism fun <A> head(a : List<A>) : A {

    return a[0] } • Same implementation for all types.
  54. 80.

    Ad-hoc Polymorphism fun combineAll(a: Matrix, b: Matrix) : Matrix {

    return doMatrixComputation() } • Same name with different implementation. • Type Dependent. fun combineAll(a: String, b: String) : String { return a + b }
  55. 81.

    Ad-hoc Polymorphism with Type Class inline fun <reified F> combineAll(

    a: F, b: F, ev: Monoid<F> = monoidal() ): F { return ev.combine(a, b) } • Polymorphism with Type Classes. • How do I achieve this?
  56. 83.

    Define Type Class interface Monoid<F> { fun combine(a: F, b:

    F): F } val monoidMap = mutableMapOf<Class""<*>, Monoid"<*">>()
  57. 84.

    Define Instances of Type Class val monoidMap = mutableMapOf<Class""<*>, Monoid"<*">>()

    monoidMap[String"::class.java] = object: Monoid<String> { override fun combine(a: String, b: String): String { return a + b } }
  58. 85.

    Define Instances of Type Class val monoidMap = mutableMapOf<Class""<*>, Monoid"<*">>()

    monoidMap[Matrix"::class.java] = object: Monoid<Matrix> { override fun combine(a: Matrix, b: Matrix): Matrix { return addMatricies(a, b) } }
  59. 86.

    Getting Instances of Type Class val monoidMap = mutableMapOf<Class""<*>, Monoid"<*">>()

    inline fun <reified F> monoidal(): Monoid<F> { return monoidMap[F"::class.java] as Monoid<F> }
  60. 87.

    Ad-hoc Polymorphism with Type Class inline fun <reified F> combineAll(

    a: F, b: F, ev: Monoid<F> = monoidal() ): F { return ev.combine(a, b) }
  61. 88.

    Ad-hoc Polymorphism with Type Class inline fun <reified F> combineAll(

    a: F, b: F, ev: Monoid<F> = monoidal() ): F { return ev.combine(a, b) } combineAll(matrix, matrix) combineAll("Hello", "World")
  62. 89.

    Type Classes in Λrrow @typeclass interface Functor<F> : TC {

    fun <A, B> map(fa: HK<F, A>, f: (A) -> B): HK<F, B> }
  63. 90.

    Type Classes Instance in Λrrow @instance(Option"::class) interface OptionFunctorInstance : Functor<OptionHK>

    { override fun <A, B> map( fa: OptionKind<A>, f: kotlin.Function1<A, B> ): Option<B> = fa.ev().map(f) }
  64. 91.
  65. 93.

    Type Classes Proposal package intext instance object IntMonoid : Monoid<Int>

    { fun Int.combine(b: Int): Int = this + b fun empty(): Int = 0 }
  66. 95.

    Type Classes Proposal import intext.IntMonoid fun <A> add(a: A, b:

    A): A given Monoid<A> = a.combine(b) add(1, 1) "// compiles add("a", "b") "// does not compile: No `String: Monoid`
  67. 96.

    Swift Extension Protocols extension Int : Monoid { static func

    e() "-> Int { return 0 } } extension Bool : Monoid { static func e() "-> Bool { return false } }
  68. 98.
  69. 99.
  70. 100.
  71. 101.