Slide 1

Slide 1 text

Functional Programming with Λrrow Mohit Sarveiya

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Functional Programming with Λrrow • Data Types • Optics • Error Handling • Type Classes • Types of Polymorphism • Ad-hoc Polymorphism • Type classes proposal for Kotlin

Slide 5

Slide 5 text

Optics Iso Lens

Slide 6

Slide 6 text

Optics Iso Lens

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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) }

Slide 10

Slide 10 text

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) }

Slide 11

Slide 11 text

Isomorphism point2DToCords: Point2D "-> Cords cordsToPoint2D: Cords "-> Point2D

Slide 12

Slide 12 text

Isomorphism Source: Focus: f ≇ g = IdA g ≇ f = IdS f: "-> g: "-> S A S A A S

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

Isomorphism val pointIsoCords : Iso = Iso( get = { point !-> Cords(point.x, point.y) }, reverseGet = { cords !-> Point2D(cords.x, cords.y) } )

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

Isomorphism val cords = Cords(6, 10) val point2D: Point2D = pointIsoCords.reverseGet(cords) "// Point2D(6, 10)

Slide 17

Slide 17 text

data class Point2D data class Tuple2 (val x: Int, val y: Int) Isomorphism (val x: Int, val y: Int)

Slide 18

Slide 18 text

data class Tuple2(val a: A, val b: B) Isomorphism data class Tuple3(val a: A, val b: B, val c: C) data class Tuple4("..)

Slide 19

Slide 19 text

val pointIsoTuple: Iso> = Iso( get = { point !-> point.x toT point.y }, reverseGet = { tuple !-> Point2D(tuple.a, tuple.b) } ) Isomorphism

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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)

Slide 22

Slide 22 text

@Retention(SOURCE) @Target(CLASS) annotation class isos Generating Isomorphism

Slide 23

Slide 23 text

Generating Isomorphism @isos data class Point2D (val x: Int, val y: Int)

Slide 24

Slide 24 text

Optics Iso Lens

Slide 25

Slide 25 text

Lens Source: S Purpose: Set, Get, Copy an immutable data structure through functional references.

Slide 26

Slide 26 text

Lens Lens Get : S "-> A Set : A "-> (S "-> S)

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

Lens data class Person(val name: String, val age: Int) val personNameLens : Lens = Lens( get = { person !-> person.name }, set = { newName !-> {foo !-> foo.copy(name = newName)} } )

Slide 29

Slide 29 text

Lens val person = Person("John Doe", 100) val personNameLens : Lens = Lens( get = { person !-> person.name }, set = { newName !-> {foo !-> foo.copy(name = newName)} } )

Slide 30

Slide 30 text

Lens val person = Person("John Doe", 100) val newPerson = personNameLens.set(person, "John Doe Jr”) // Person(name=John Doe Jr, age=100)

Slide 31

Slide 31 text

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)

Slide 32

Slide 32 text

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)

Slide 33

Slide 33 text

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() ) ) ) )

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

data class Company(val name: String, val address: Address) Lens val companyAddress: Lens = Lens( get = { it.address }, set = { address !-> { company !-> company.copy(address = address) } }) val address: Address)

Slide 37

Slide 37 text

data class Address(val city: String, val street: Street) Lens val addressStreet: Lens = Lens( get = { it.street }, set = { street !-> { address !-> address.copy(street = street) } }) val street: Street)

Slide 38

Slide 38 text

data class Street(val number: Int, val name: String) Lens val streetName: Lens = Lens( get = { it.name }, set = { name !-> { street !-> street.copy(name = name) } } ) val name: String)

Slide 39

Slide 39 text

Lens val employeeStreetName = employeeCompany compose companyAddress compose addressStreet compose streetName val employee = employeeStreetName.modify( employee, String"::capitalize) // Employee(name=John Doe, ... name=Hacker Way))))

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

Generating Lenses @Retention(SOURCE) @Target(CLASS) annotation class lenses

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

Error Handling Option Either Try

Slide 44

Slide 44 text

Error Handling Option Either Try

Slide 45

Slide 45 text

val books : List? = getBooks()

Slide 46

Slide 46 text

val books : List? = getBooks() books"?.map { ""... } books"?.flatMap { ""... } books"?.fold(""...)

Slide 47

Slide 47 text

val book : Book? = getBookForId(1000)

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

Option A Some None

Slide 50

Slide 50 text

sealed class Option { object None : Option() data class Some(val t: T) : Option() }

Slide 51

Slide 51 text

val option : Option = getBookForId(1000) fun getBookForId(id : Int) : Option { val book : Book? = getAllBooksFromDB().find { it.id "== id } return if (book "!= null) { Some(book) } else { None } }

Slide 52

Slide 52 text

val option : Option = getBookForId(1000) fun getBookForId(id : Int) : Option { val book : Book? = getAllBooksFromDB().find { it.id "== id } } return if (book "!= null) { Some(book) } else { None }

Slide 53

Slide 53 text

val option : Option = getBookForId(1000) fun T?.toOption(): Option = if (this != null) { Some(this) } else { None }

Slide 54

Slide 54 text

val option : Option = getBookForId(1000) fun getBookForId(id : Int) : Option { return getAllBooksFromDB() .find { it.id "== id } .toOption() }

Slide 55

Slide 55 text

val option : Option = getBookForId(1000) val totalPrice: Option = option.map { book !-> book.price + tax }

Slide 56

Slide 56 text

val option : Option = getBookForId(1000) val description = option.fold( ifEmpty = { "No Description" }, some = { it.description } )

Slide 57

Slide 57 text

Error Handling Option Either Try

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

try { val reciprocal = reciprocal(2) compute(reciprocal) } catch (e: IllegalArgumentException) { log("Failed to take reciprocal”) }

Slide 61

Slide 61 text

Either A Left Right B

Slide 62

Slide 62 text

sealed class Either { data class Left(val a: A) : Either() data class Right(val b: B) : Either() }

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

fun reciprocal(i: Int): { return if (i == 0) { } else { 1.0 / i } } Either.left(IllegalArgumentException(“Can’t be 0") Either

Slide 66

Slide 66 text

fun reciprocal(i: Int): { return if (i == 0) { } else { } } Either.left(IllegalArgumentException(“Can’t be 0") Either Either.right(1.0 / i)

Slide 67

Slide 67 text

fun reciprocal(i: Int): { return if (i == 0) { } else { } } Either.left(IllegalArgumentException(“Can’t be 0") Either Either.right(1.0 / i)

Slide 68

Slide 68 text

val either: Either = reciprocal(2)

Slide 69

Slide 69 text

val either: Either = reciprocal(2) when(either) { is Either.Left "-> log("Failed to take reciprocal") is Either.Right "-> compute(either.b) }

Slide 70

Slide 70 text

Error Handling Option Either Try

Slide 71

Slide 71 text

fun reciprocal(i: Int): Double { if (i == 0) throw IllegalArgumentException(“Can’t be 0") return 1.0 / i } External Library

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

val reciprocal = Try { reciprocal(2) }.getOrDefault { 1.0 }

Slide 74

Slide 74 text

Try { reciprocal(0) }.fold( { t: Throwable !-> log("Failed to take reciprocal", t) }, { num: Double !-> compute(num) })

Slide 75

Slide 75 text

sealed class Try { data class Failure(val e: Throwable) : Try() data class Success(val value: A) : Try() }

Slide 76

Slide 76 text

Adhoc Polymorphism & Type Classes

Slide 77

Slide 77 text

Type Classes Functor, Monad, Monoid, Applicative … Type Constructors Option, Try, Either, IO, Ior, Reader, State

Slide 78

Slide 78 text

Polymorphism Ad-hoc Universal Overloading Coercion Inclusion Parametric

Slide 79

Slide 79 text

Slide 80

Slide 80 text

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 }

Slide 81

Slide 81 text

Ad-hoc Polymorphism with Type Class inline fun combineAll( a: F, b: F, ev: Monoid = monoidal() ): F { return ev.combine(a, b) } • Polymorphism with Type Classes. • How do I achieve this?

Slide 82

Slide 82 text

Define Type Class interface Monoid { fun combine(a: F, b: F): F }

Slide 83

Slide 83 text

Define Type Class interface Monoid { fun combine(a: F, b: F): F } val monoidMap = mutableMapOf, Monoid"<*">>()

Slide 84

Slide 84 text

Define Instances of Type Class val monoidMap = mutableMapOf, Monoid"<*">>() monoidMap[String"::class.java] = object: Monoid { override fun combine(a: String, b: String): String { return a + b } }

Slide 85

Slide 85 text

Define Instances of Type Class val monoidMap = mutableMapOf, Monoid"<*">>() monoidMap[Matrix"::class.java] = object: Monoid { override fun combine(a: Matrix, b: Matrix): Matrix { return addMatricies(a, b) } }

Slide 86

Slide 86 text

Getting Instances of Type Class val monoidMap = mutableMapOf, Monoid"<*">>() inline fun monoidal(): Monoid { return monoidMap[F"::class.java] as Monoid }

Slide 87

Slide 87 text

Ad-hoc Polymorphism with Type Class inline fun combineAll( a: F, b: F, ev: Monoid = monoidal() ): F { return ev.combine(a, b) }

Slide 88

Slide 88 text

Ad-hoc Polymorphism with Type Class inline fun combineAll( a: F, b: F, ev: Monoid = monoidal() ): F { return ev.combine(a, b) } combineAll(matrix, matrix) combineAll("Hello", "World")

Slide 89

Slide 89 text

Type Classes in Λrrow @typeclass interface Functor : TC { fun map(fa: HK, f: (A) -> B): HK }

Slide 90

Slide 90 text

Type Classes Instance in Λrrow @instance(Option"::class) interface OptionFunctorInstance : Functor { override fun map( fa: OptionKind, f: kotlin.Function1 ): Option = fa.ev().map(f) }

Slide 91

Slide 91 text

No content

Slide 92

Slide 92 text

Type Classes Proposal typeclass Monoid { fun A.combine(b: A): A fun empty(): A }

Slide 93

Slide 93 text

Type Classes Proposal package intext instance object IntMonoid : Monoid { fun Int.combine(b: Int): Int = this + b fun empty(): Int = 0 }

Slide 94

Slide 94 text

Type Classes Proposal import intext.IntMonoid 1.combine(2) "// 3 Int.empty() "// 0

Slide 96

Slide 96 text

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

Slide 97

Slide 97 text

Suggestions to Learn more!

Slide 98

Slide 98 text

No content

Slide 99

Slide 99 text

No content

Slide 100

Slide 100 text

No content

Slide 101

Slide 101 text

No content

Slide 102

Slide 102 text

Thank you! twitter.com/heyitsmohit
 github.com/msya