Mohit S
January 24, 2018
1.4k

# Functional Programming with Arrow

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

January 24, 2018

## Transcript

2. ### Functional Programming with Λrrow • Data Types • Optics •

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

5. ### data class Point2D data class Cords (val x: Int, val

y: Int) Isomorphism (val x: Int, val y: Int)
6. ### data class Point2D data class Cords (val x: Int, val

y: Int) Isomorphism (val x: Int, val y: Int)
7. ### 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) }
8. ### 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) }

10. ### Isomorphism Source: Focus: f ≇ g = IdA g ≇

f = IdS f: "-> g: "-> S A S A A S
11. ### 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 }
12. ### Isomorphism val pointIsoCords : Iso<Point2D, Cords> = Iso( get =

{ point !-> Cords(point.x, point.y) }, reverseGet = { cords !-> Point2D(cords.x, cords.y) } )
13. ### Isomorphism val point = Point2D(6, 10) val cords: Cords =

pointIsoCords.get(point) "// Cords(6, 10)
14. ### Isomorphism val cords = Cords(6, 10) val point2D: Point2D =

pointIsoCords.reverseGet(cords) "// Point2D(6, 10)
15. ### data class Point2D data class Tuple2 (val x: Int, val

y: Int) Isomorphism (val x: Int, val y: Int)
16. ### 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>("..)
17. ### val pointIsoTuple: Iso<Point2D, Tuple2<Int, Int">> = Iso( get = {

point !-> point.x toT point.y }, reverseGet = { tuple !-> Point2D(tuple.a, tuple.b) } ) Isomorphism
18. ### 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
19. ### 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)

y: Int)

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

structure through functional references.
24. ### Lens Lens<S, A> Get : S "-> A Set :

A "-> (S "-> S)

26. ### 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)} } )
27. ### Lens val person = Person("John Doe", 100) val personNameLens :

Lens<Person, String> = Lens( get = { person !-> person.name }, set = { newName !-> {foo !-> foo.copy(name = newName)} } )
28. ### Lens val person = Person("John Doe", 100) val newPerson =

personNameLens.set(person, "John Doe Jr”) // Person(name=John Doe Jr, age=100)
29. ### 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)

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

class Employee(val name: String, val company: Company)
33. ### 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) } } )

35. ### 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)
36. ### 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)
37. ### Lens val employeeStreetName = employeeCompany compose companyAddress compose addressStreet compose

streetName val employee = employeeStreetName.modify( employee, String"::capitalize) // Employee(name=John Doe, ... name=Hacker Way))))
38. ### 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)

Company)

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

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

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

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

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

class Some<out T>(val t: T) : Option<T>() }
49. ### 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 } }
50. ### 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 }
51. ### val option : Option<Book> = getBookForId(1000) fun <T> T?.toOption(): Option<T>

= if (this != null) { Some(this) } else { None }
52. ### val option : Option<Book> = getBookForId(1000) fun getBookForId(id : Int)

: Option<Book> { return getAllBooksFromDB() .find { it.id "== id } .toOption() }
53. ### val option : Option<Book> = getBookForId(1000) val totalPrice: Option<Int> =

option.map { book !-> book.price + tax }
54. ### val option : Option<Book> = getBookForId(1000) val description = option.fold(

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

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

IllegalArgumentException("Can’t be 0") return 1.0 / i }
57. ### throw IllegalArgumentException(“Can’t be 0") fun reciprocal(i: Int): Double { if

(i == 0) return 1.0 / i }
58. ### try { val reciprocal = reciprocal(2) compute(reciprocal) } catch (e:

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

60. ### 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>() }
61. ### fun reciprocal(i: Int): Double { if (i == 0) throw

IllegalArgumentException(“Can’t be 0") return 1.0 / i }
62. ### fun reciprocal(i: Int): { if (i == 0) throw IllegalArgumentException(“Can’t

be 0") return 1.0 / I } Either<Throwable, Double>
63. ### fun reciprocal(i: Int): { return if (i == 0) {

} else { 1.0 / i } } Either.left(IllegalArgumentException(“Can’t be 0") Either<Throwable, Double>
64. ### fun reciprocal(i: Int): { return if (i == 0) {

} else { } } Either.left(IllegalArgumentException(“Can’t be 0") Either<Throwable, Double> Either.right(1.0 / i)
65. ### fun reciprocal(i: Int): { return if (i == 0) {

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

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

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

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

IllegalArgumentException(“Can’t be 0") return 1.0 / i } External Library
70. ### var reciprocal : Double = try { reciprocal(0) } catch

(e: IllegalArgumentException) { 1.0 }

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

take reciprocal", t) }, { num: Double !-> compute(num) })
73. ### 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>() }

75. ### Type Classes Functor, Monad, Monoid, Applicative … Type Constructors Option,

Try, Either, IO, Ior, Reader, State

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

return a[0] } • Same implementation for all types.
78. ### 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 }
79. ### 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?

F): F }
81. ### Define Type Class interface Monoid<F> { fun combine(a: F, b:

F): F } val monoidMap = mutableMapOf<Class""<*>, Monoid"<*">>()
82. ### 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 } }
83. ### 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) } }
84. ### 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> }
85. ### 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) }
86. ### 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")
87. ### Type Classes in Λrrow @typeclass interface Functor<F> : TC {

fun <A, B> map(fa: HK<F, A>, f: (A) -> B): HK<F, B> }
88. ### 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) }
89. ### Type Classes Proposal typeclass Monoid<A> { fun A.combine(b: A): A

fun empty(): A }
90. ### Type Classes Proposal package intext instance object IntMonoid : Monoid<Int>

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

0
92. ### 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`
93. ### Swift Extension Protocols extension Int : Monoid { static func

e() "-> Int { return 0 } } extension Bool : Monoid { static func e() "-> Bool { return false } }