Successfully reported this slideshow.
Your SlideShare is downloading. ×

Functional programming in kotlin with Arrow [Sunnytech 2018]

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Loading in …3
×

Check these out next

1 of 37 Ad

Functional programming in kotlin with Arrow [Sunnytech 2018]

Download to read offline

Slides from my talk about Kotlin & Functional programming with Arrow which I gave at Sunny Tech 2018 (http://sunny-tech.io)
It showcases how Kotlin is a good fit for functional programming, thanks to Arrow.

Slides from my talk about Kotlin & Functional programming with Arrow which I gave at Sunny Tech 2018 (http://sunny-tech.io)
It showcases how Kotlin is a good fit for functional programming, thanks to Arrow.

Advertisement
Advertisement

More Related Content

Advertisement
Advertisement

Functional programming in kotlin with Arrow [Sunnytech 2018]

  1. 1. Functional Programming in Kotlin with Arrow Emmanuel Nhan - 28/06/2018
  2. 2. /me ! • Backend engineer at Sigfox • Mostly OOP by day (Java, Spring 😒) but FP enthusiast • FP by night & evangelization at work • Not FP expert • @nhanmanu on Twitter
  3. 3. Scope Functional Programming: Using pure functions Strongly typed Using techniques found in Scala Kotlin (v1.2.x): Focus on JVM only Idioms to build FP machinery Arrow (v0.7.2): How it works Overview of core
  4. 4. Functional Programming • Functions, high order functions • Immutable data • Referential Transparency • Abstractions • Lazy evaluation
  5. 5. Kotlin ? • Hype 🤩 • Language tasting like Java with lots of sugar 🍯 • Inspired by many existing languages • Runs on JVM ( including Android), JS, Native • Developed by Jetbrains • First class citizen in Android, Spring, Reactor,…
  6. 6. Why FP in Kotlin on JVM ? • When the team is too scared by Scala • Idioms which make FP possible & enjoyable • But concepts are missing : 
 need to emulate them
  7. 7. Functions
  8. 8. Functions // Declaring a simple function fun add(a: Int, b: Int): Int = a + b // Or val minus: (Int, Int) -> Int = { a, b -> a - b} // With generics & high order ! fun <A, B, C> compose(f: (A) ->B, g: (B) ->C ): (A) ->C = { a: A -> g(f(a))} Function definition Return typeParameters
  9. 9. Extension Functions • Feature allowing to add functions to an exiting type // Enriching Int : fun Int.minus3(): Int = this - 3 // Works also with generics fun <A, B, C> ((A, B) ->C).partial(a: A): (B) ->C = {b: B -> this(a, b)} • Using this syntax: 6.minus3() val plus4: (Int) ->Int = ::add.partial(4)
  10. 10. Immutable Data Structures
  11. 11. Types: data classes data class Message(val author: String, val recipient: String, val content: String) declares fields which are not reassignable
  12. 12. object • Allows to declare singletons: object Bar • companion object adds methods « to the type itself » // Declaration class Foo { // ... companion object { fun bar(): Int = TODO() } } // Use Foo.bar()
  13. 13. Types: hierarchy Any Nothing Every single type declared in the application Nothing is called the bottom type : it inherits from all
  14. 14. Types: Option sealed class Option<out T> data class Some<out T>(val t: T): Option<T>() object None: Option<Nothing>() // Usage: val a: Option<Int> = Some(4) val r = when(a){ is Some -> a.t is None -> 0 } Not really pattern matching but… inheritance
  15. 15. Types: recursive structure sealed class LinkedList<out A> data class Cons<A>( val head: A, val tail: LinkedList<A> ): LinkedList<A>() object Nil: LinkedList<Nothing>()
  16. 16. Abstractions
  17. 17. Ad-hoc polymorphism • Technique popularized by Haskell (typeclasses) • A set of pure functions to fulfill a contract (laws) • Abstraction over a general property • No native support in Kotlin (yet)
  18. 18. Order Typeclass interface Order<T> { /** * Compare [x] with [y]. * Returns an Int whose sign is: * - negative if `x < y` * - zero if `x = y` * - positive if `x > y` */ fun compare(x: T, y: T): Int }
  19. 19. Order Typeclass instance object IntOrderInstance: Order<Int> { override fun compare(x: Int, y: Int): Int
 = when { x < y -> -1 x > y -> 1 else -> 0 } }
  20. 20. Usage of Order /** * Sort [list] in croissant order. * Typeclass instance passing by parameter */ fun <T> sort(list: List<T>, O: Order<T>): List<T> = TODO() Sorting requires a property of ordering
  21. 21. Higher Kinds 101 • Let’s say we have a typeclass SomeTC<F> • Constraint on F : to be a type shaped like SomeType<A> • SomeType<A> is a type constructor
 with one parameter: A • Reasoning on theses shapes allows better abstractions
  22. 22. Higher Kind emulation // Kind definition interface Kind<out F, out A> typealias Kind2<F,A,B> = Kind<Kind<F,A>,B> typealias Kind3<F,A,B,C> = Kind<Kind2<F,A,B>,C> Type aliasing: makes code more readable Type constructor parameter Marker type independent of A
  23. 23. Higher Kind emulation • Going back to our LinkedList<A> • Its shape is Kind<F, A> class ForLinkedList private constructor() typealias LListOf<A> = Kind<ForLinkedList, A> sealed class LinkedList<out A>: LListOf<A> { //…
  24. 24. Higher Kinds & Typeclasses interface Functor<F> { fun <A, B> map(v: Kind<F, A> ,f: (A) -> B): Kind<F, B> } // Emulation drawback : downcasting… val l: Kind<ForLinkedList, Int> = //Some call to map() val fixed: LinkedList<Int> = l.fix() // Definition of fix()😱 : fun <A> OptionOf<A>.fix(): Option<A> = this as Option<A> Need to downcast !
  25. 25. We can do better
  26. 26. Meet Arrow • A library based on the principles we just saw • Inspired by Cats & Scalaz from Scala ecosystem • Uses code generation (for now) to reduce boilerplate • Lots of modules & contributors • Integrates with other libraries from the Kotlin ecosystem
  27. 27. Arrow typeclasses • Provides extensions methods : interface Functor<F> { fun <A, B> Kind<F, A>.map(f: (A) -> B): Kind<F, B> } • Still no way to avoid fix() . Go vote for KEEP-87 ! • Provides instances for common datatypes • Uses KAPT to generate boilerplate • Enhanced syntax
  28. 28. Option val a: Option<Int> = 3.some() val b: Option<Int> = 5.some() val res: Option<Int> = a.flatMap { x -> b.map { it + x } }
  29. 29. Option 2 val a: Option<Int> = 3.some() val b: Option<Int> = 5.some() val res = ForOption extensions { binding { a.bind() + b.bind() }.fix() }
  30. 30. Sample: Validation // THE CONTEXT import arrow.core.* import arrow.data.* typealias AppRawConfig = MapK<String, String> fun retrieveConf(): AppRawConfig = TODO() To use Arrow easily
  31. 31. Either & Option val conf = retrieveConf() val someParam: Either<String, Int> = conf.getOption("someParam" ).fold( { "Could not find someParam".left() },{ toParse -> val nullable: Int? = toParse.toIntOrNull() nullable.toOption().fold({ "someParam is not an Int".left() },{ it.right() }) } ) Addition from MapK Extension Method Kotlin feature
  32. 32. Accumulating failures • We need a similar structure to Either<L,R> : Validated<E,A> • How to accumulate values on the E type ? • NonEmptyList<A> or Nel<A> makes sure a list contains at least one element • We will accumulate in Validated<Nel<String>, T>
  33. 33. ValidatedNel val otherParam: Either<String, Int> = //TODO() val someParamV: Validated<String, Int> = Validated.fromEither(someParam) val otherParamV: Validated<String, Int> = Validated.fromEither(otherParam) val someParamVNel: ValidatedNel<String, Int> = someParamV.toValidatedNel() Lifting Either to Validated Transforming the left type to Nel
  34. 34. Accumulating data class SomeConfig(val a: Int, val b: Int) val otherParamVNel: ValidatedNel<String, Int> = // … val result: ValidatedNel<String, SomeConfig> = ValidatedNel.applicative( Nel.semigroup<String>() ) .map(someParamVNel, otherParamVNel){ t -> SomeConfig(t.a, t.b) }.fix()
  35. 35. More Arrow • Optics • Recursion schemes • Integration with Kotlin coroutines, RxJava, Reactor,… • IO • Uses much more Kotlin idioms (delegation,…)
  36. 36. Thank you ! Any questions ?
  37. 37. Resources & links • https://kotlinlang.org/ • https://arrow-kt.io/ • https://gitter.im/arrow-kt/Lobby • https://typelevel.org/cats/typeclasses.html • https://www.pacoworks.com/2018/02/25/simple- dependency-injection-in-kotlin-part-1/

×