SlideShare ist ein Scribd-Unternehmen logo
1 von 44
Downloaden Sie, um offline zu lesen
Kotlin und Arrow
ein Duo für FP
Stefan López Romero & Felicitas Hörmann
MaibornWolff GmbH
14.01.2021
Speaker
Stefan López Romero
IT Architect @MaibornWolff GmbH
Felicitas Hörmann
So ware Engineer @MaibornWolff GmbH
Ziel des Vortrags
Vorstellung von Kotlin als funk onalere Java-Alterna ve
kurzer Einblick in die bekannteste Kotlin-Library für FP: Arrow
So leicht ist der Wechsel
einfacher Ums eg für Java-Entwickler dank hoher Java-Nähe
extrem hohe Interoperabilität zwischen Java und Kotlin
Java-zu-Kotlin-Converter in IntelliJ enthalten
problemlose Nutzung fast aller Java-Libraries möglich
Kotlin Features
Was bietet Kotlin?
viele unterstützte Einsatzbereiche
objektorien erte und funk onale Komponenten
prägnante Syntax (circa 40 % weniger Codezeilen als Java)
Variablen & Typinferenz
Variablen werden mit val (immutable) oder var (mutable) gekennzeichnet
Typen können op onal angegeben werden
val firstSpeaker = "Felicitas"
val secondSpeaker: String = "Stefan"
es gibt keine primi ven Typen (werden nur im Bytecode verwendet)
Null-sichere Typen
Unterscheidung zwischen nullable und non-null Referenzen
Compiler erkennt, wenn eine Variable möglicherweise null ist
fun main() {
val nonNullable: String = "Alice" // non-nullable
val nullable: String? = "Bob" // nullable
println(nonNullable.length)
println(nullable.length) // compiler error
}
viele Möglichkeiten zum Umgang mit nullable Referenzen (safe (?.) or non-null asserted (!!.)
calls, elvis (?:), if)
auch Chaining möglich
val streetName = order?.customer?.address?.streetName ?: ''
Data Classes
data class Person(val name: String, val age: Int)
fun main() {
println(Person("Sherlock", 30)) // Person(name=Sherlock, age=30)
}
Automa sche Generierung von
equals()
toString()
copy()
hashcode()
componentN() func ons (for destructuring)
Extension Methods
unterstützt bessere Modularisierung
fun Int.addThree() = this + 3
fun main() {
print(4.addThree()) // 7
}
Lambdas & Funk onstypen
Java unterstützt nur Func onal Interfaces (a.k.a. SAM)
import java.util.function.Predicate;
public class EvenChecker implements Predicate<Integer> {
public boolean test(Integer integer) {
return integer % 2 == 0;
}
public static void main(String[] args){
System.out.println(new EvenChecker().test(12));
}
}
Seit Java 8 können Lambdas als Implemen erung von funk onalen Interfaces verwendet werden
import java.util.function.Predicate;
class Main {
public static void main(String[] args) {
Predicate<Integer> isEven = a -> a % 2 == 0;
System.out.println(isEven.test(12));
}
}
Kotlin unterstützt echte Funk onstypen und behandelt Funk onen als first class ci zens
fun main() {
val isEven = { a: Int -> a % 2 == 0 }
println(isEven(12))
println(isEven) // (kotlin.Int) -> kotlin.Boolean
}
Typen können auch hier angegeben werden
fun main() {
val greet: (String) -> String = {name -> "Hello $name!"}
println(greet("JUGHH")) // Hello JUGHH!
println(greet) // (kotlin.String) -> kotlin.String
}
Higher Order Func ons & Par elle Funk onsanwendung
fun main() {
val greet: (getName: (Int) -> String) -> (id: Int) -> String =
{ getName -> { id -> "Hello ${getName(id)}!" } }
val getNameForId: (Int) -> String =
when(id) {
1 -> "Maria"
2 -> "Anna"
else -> "Stranger"
}
println(greet(getNameForId)) // (kotlin.Int) -> kotlin.String
println(greet(getNameForId)(1)) // Hello Maria!
}
Type Aliases
erleichtert die Verwendung komplexer Typen
typealias Predicate<T> = (T) -> Boolean
Aggregate Opera ons
in Java mit Hilfe von Streams möglich
import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> doubledList = list
.stream()
.map(n -> 2 - n)
.collect(Collectors.toList());
System.out.println(doubledList); // [2, 4, 6, 8, 10]
}
}
in Kotlin straigh orward
fun main() {
val list: List<Int> = listOf(1, 2, 3, 4, 5);
// trailing lambda
// it für single lambda parameter
val doubledList = list.map { it - 2 }
val gaussianSum = (1..100).toList().reduce(Int::plus)
}
min(), max(), average(), sum() & Versionen mit explizitem Comparator
fold(), reduce() (beide le ) & right-, indexed- und "orNull"-Versionen
Was fehlt Kotlin?
Sprach-Features
Higher Kinded Types
Typ-Klassen
Library-Features
Funk onen zur Komposi on und für (Un-)Currying
Funk onale Datentypen (Op on, Either etc.)
Abstrak onen (Funktoren, Monaden etc.)
Kotlin Arrow
Was ist Arrow
Stdlib für FP in Kotlin
Fusion aus KATEGORY und funKTionale
Erstes Release 2018
Thoughtworks Tech Radar: Kategorie Adopt
Was bietet Arrow
Arrow-Core: Funk onale Std-Lib (Basis)
Basis Funk onen ( compose , curry ...)
Funk onale Datentypen ( Option , Either ...)
Emula on: Higher Kinded Types
Typ-Klassen
Arrow-Fx: Seiteneffekte funk onal handhaben
Arrow-Op cs: Transforma on von immutable Daten
Basis Funk onen in Arrow
Funk onskomposi on
Funk onskomposi on ist das Mi el um größere Programme durch Kombina on von einzelnen
Funk onen zu schreiben.
Seien A, B, C beliebige Mengen und
g: A ➝ B sowie f: B ➝ C Funk onen,
so heißt die Funk on
f ° g : A ➝ C , (f ° g)(x) = f(g(x))
Komposi on von f und g
Funk onskomposi on mit Arrow
Arrow bietet hierfür die Funk onen compose , andThen , forwardCompose
val parse: (String) -> Int = { it.toInt()}
val addOne: (Int) -> Int = { it + 1 }
val parseAddOne1: (String) -> Int = addOne.compose(parse)
val result = parseAddOne1("5") // = 6 ≙ addOne(parse("5"))
val parseAddOne2: (String) -> Int = parse.andThen(addOne)
val parseAddOne3: (String) -> Int = parse.forwardCompose(addOne)
Currying
Currying ist die Umwandlung einer Funk on mit mehreren Argumenten in eine gleichwer ge
Sequenz von Funk onen
mit jeweils einem Argument.
fun <A, B, C> ((A, B)-> C).curry() : (A) -> ((B) -> C) = {
a -> { b -> this(a, b)}
}
Currying mit Arrow
Arrow bietet hierfür die Funk onen curry und uncurry
val calcTax: (Double, Double) -> Double = {
value, rate -> value - rate
}
val calcTaxCurried: (Double) -> (Double) -> Double =
calcTax.curried()
val calcVat = calcTaxCurried(0.19)
val vat = calcVat(149.99)
val vat2 = calcTaxCurried.uncurried()(0.19, 149.99)
Par elle Funk onsanwendung
Arrow bietet hierfür die Funk onen partially2 bis partially22
val calcTaxForRate: (Double) -> Double =
calcTax.partially2(149.99);
val reducedVat = calcTaxForRate(0.07);
val Vat = calcTaxForRate(0.19);
Funk onale Datentypen in Arrow
Eine Auswahl
Option
Either
ListK , SetK , MapK
NonEmptyList
...
Typklassen in Arrow
Typklassen als höhere Abstrak onen
Design-Pa erns der Funk onalen Programmierung
Keine Klassen im OOP Sinne
Eher wie Interfaces auf sehr abstrakter Ebene
Besteht aus Algebra ≙ Funk onen und Gesetze ≙ Verhalten
Die Funk on map
//List
var l: List<Int> = listOf("1", "2", "3", "4").map { it.toInt() }
//Option
var o:Option<Int> = Some("1").map { it.toInt() }
Die Signatur von map
//List
fun <A, B> List<A>.map(f: (A) -> B): List<B>
//Option
fun <A, B> Option<A>.map(f: (A) -> B): Option<B>
Typklasse Functor
interface Functor<F> {
fun <A, B> F<A>.map(f: (A) -> B): F<B>
}
F<A> was ist das?
Higher kinded Types mit Arrow
Mit dem Interface Kind lässt sich unser Problem lösen
interface Kind<out F, out A>
interface Functor<F> {
fun <A, B> Kind<F, A>.map(f: (A) -> B): Kind<F, B>
}
Datentyp für op onale Werte
@higherkind
sealed class Option<out A> : Kind<ForOption, A> {
companion object
}
data class Some<out A>(val get: A) : Option<A>()
object None : Option<Nothing>()
Arrow generiert helper
ForOption als Ersatztyp für Option<A> ohne den generischen Typ-Parameter.
Es wird sichergestellt, dass Option<A> die einzige Implemen erung von Kind<ForOption,
A> ist.
fix Funk on zur Umwandlung von Kind<ForOption, A> zu Option<A>
Option<A> zu Kind<ForOption, A> via subclassing
Funktor für Option
@extension
interface OptionFunctor : Functor<ForOption> {
override fun <A, B> Kind<ForOption, A>.map(f: (A) -> B): Option<B> {
val option : Option<A> = this.fix()
return when(option) {
is None -> None
is Some -> Some(f(option.get))
}
}
}
@extension :
generiert ein Objekt aus dem interface mit allen bereits definierten default-methoden
erweitert das companion object von Option um eine Funk on functor() , die das
Objekt zurückgibt
Anwendungsbeispiel
fun <F> abs(fa: Kind<F, Int>, FT: Functor<F>) : Kind<F, Int> =
FT.run {
fa.map { when {
it < 0 -> - it
else -> it
} }
}
val res1 = abs(LinkedList(1,-2, -3), LinkedList.functor()).fix() // [1, 2, 3]
val res2 = abs(Some(-2), Option.functor()).fix() // 2
Iden tät eines Funktors
Abbildung auf sich selbst ≙ unveränderter Funktor
fun <F, A> identity(fa: Kind<F, A>,
FT: Functor<F> ) : Boolean =
FT.run {
fa.map { it } == fa
}
Assozia vität eines Funktors
Mehrere map Funk onen nacheinander ≙ Komposi on beider map Funk onen
fun <F, A, B, C> associativity(fa: Kind<F, A>,
FT: Functor<F>, f: (A)-> B, g:(B) -> C) : Boolean =
FT.run {
fa.map(f).map(g) == fa.map(f.andThen(g))
}
Sind die Gesetze erfüllt?
assert(identity(Some(3), Option.functor()))
val parseInt : (String) -> Int = { s -> Integer.parseInt(s)}
val plusOne : (Int) -> Int = { x:Int -> x.plus(1)}
assert(associativity(Some("1"), Option.functor(), parseInt, plusOne))
Unser Eindruck
Arrow ist ein gut strukturierter Baukasten
Advanced FP ist auch mit Kotlin möglich
Simula on von Higher Kinded Types etwas gewöhnungsbedür ig
Code-Generierung macht manchmal Probleme
Im Projekt definieren, was aus dem Baukasten verwendet werden darf/soll.
Ich will mehr davon
Func onal Programming in Kotlin - Manning
Kotlin Koans - zum Kennenlernen von Kotlin

Weitere ähnliche Inhalte

Ähnlich wie Slides

Go - Googles Sprache für skalierbare Systeme
Go - Googles Sprache für skalierbare SystemeGo - Googles Sprache für skalierbare Systeme
Go - Googles Sprache für skalierbare SystemeFrank Müller
 
Einführung in die funktionale Programmierung
Einführung in die funktionale ProgrammierungEinführung in die funktionale Programmierung
Einführung in die funktionale ProgrammierungDigicomp Academy AG
 
Skalierbare Anwendungen mit Google Go
Skalierbare Anwendungen mit Google GoSkalierbare Anwendungen mit Google Go
Skalierbare Anwendungen mit Google GoFrank Müller
 
Funktionale Reaktive Programmierung mit Sodium
Funktionale Reaktive Programmierung mit SodiumFunktionale Reaktive Programmierung mit Sodium
Funktionale Reaktive Programmierung mit SodiumTorsten Fink
 
Devs@Home - Einführung in Go
Devs@Home - Einführung in GoDevs@Home - Einführung in Go
Devs@Home - Einführung in GoFrank Müller
 
Fundamentale Muster in Java
Fundamentale Muster in JavaFundamentale Muster in Java
Fundamentale Muster in Javatutego
 
Einfacher bauen
Einfacher bauenEinfacher bauen
Einfacher bauenjohofer
 
Metaprogrammierung und Reflection
Metaprogrammierung und ReflectionMetaprogrammierung und Reflection
Metaprogrammierung und ReflectionStefan Marr
 
Python - Excel - Bibliotheken
Python - Excel - BibliothekenPython - Excel - Bibliotheken
Python - Excel - BibliothekenHausmaus26
 
Übungsaufgaben SS2010
Übungsaufgaben SS2010Übungsaufgaben SS2010
Übungsaufgaben SS2010maikinger
 
Java und Python - Das Beste aus beiden Welten nutzen
Java und Python - Das Beste aus beiden Welten nutzenJava und Python - Das Beste aus beiden Welten nutzen
Java und Python - Das Beste aus beiden Welten nutzenAndreas Schreiber
 
PyLucene@PyCon DE 2011
PyLucene@PyCon DE 2011PyLucene@PyCon DE 2011
PyLucene@PyCon DE 2011Thomas Koch
 
Tech Talk: Groovy
Tech Talk: GroovyTech Talk: Groovy
Tech Talk: Groovymwie
 

Ähnlich wie Slides (20)

Go - Googles Sprache für skalierbare Systeme
Go - Googles Sprache für skalierbare SystemeGo - Googles Sprache für skalierbare Systeme
Go - Googles Sprache für skalierbare Systeme
 
Scala und Lift
Scala und LiftScala und Lift
Scala und Lift
 
Einführung in die funktionale Programmierung
Einführung in die funktionale ProgrammierungEinführung in die funktionale Programmierung
Einführung in die funktionale Programmierung
 
Skalierbare Anwendungen mit Google Go
Skalierbare Anwendungen mit Google GoSkalierbare Anwendungen mit Google Go
Skalierbare Anwendungen mit Google Go
 
Funktionale Reaktive Programmierung mit Sodium
Funktionale Reaktive Programmierung mit SodiumFunktionale Reaktive Programmierung mit Sodium
Funktionale Reaktive Programmierung mit Sodium
 
Devs@Home - Einführung in Go
Devs@Home - Einführung in GoDevs@Home - Einführung in Go
Devs@Home - Einführung in Go
 
Ruby, Ruby, Ruby!
Ruby, Ruby, Ruby!Ruby, Ruby, Ruby!
Ruby, Ruby, Ruby!
 
jQuery & CouchDB - Die zukünftige Webentwicklung?
jQuery & CouchDB - Die zukünftige Webentwicklung?jQuery & CouchDB - Die zukünftige Webentwicklung?
jQuery & CouchDB - Die zukünftige Webentwicklung?
 
Fundamentale Muster in Java
Fundamentale Muster in JavaFundamentale Muster in Java
Fundamentale Muster in Java
 
Einfacher bauen
Einfacher bauenEinfacher bauen
Einfacher bauen
 
Metaprogrammierung und Reflection
Metaprogrammierung und ReflectionMetaprogrammierung und Reflection
Metaprogrammierung und Reflection
 
Python - Excel - Bibliotheken
Python - Excel - BibliothekenPython - Excel - Bibliotheken
Python - Excel - Bibliotheken
 
Übungsaufgaben SS2010
Übungsaufgaben SS2010Übungsaufgaben SS2010
Übungsaufgaben SS2010
 
Integration camel
Integration camelIntegration camel
Integration camel
 
WiSe 2013 | Programmierpraktikum C++ - 01_Basics
WiSe 2013 | Programmierpraktikum C++ - 01_BasicsWiSe 2013 | Programmierpraktikum C++ - 01_Basics
WiSe 2013 | Programmierpraktikum C++ - 01_Basics
 
Java und Python - Das Beste aus beiden Welten nutzen
Java und Python - Das Beste aus beiden Welten nutzenJava und Python - Das Beste aus beiden Welten nutzen
Java und Python - Das Beste aus beiden Welten nutzen
 
BIT I WiSe 2014 | Basisinformationstechnologie I - 08: Programmiersprachen I
BIT I WiSe 2014 | Basisinformationstechnologie I - 08: Programmiersprachen IBIT I WiSe 2014 | Basisinformationstechnologie I - 08: Programmiersprachen I
BIT I WiSe 2014 | Basisinformationstechnologie I - 08: Programmiersprachen I
 
PyLucene@PyCon DE 2011
PyLucene@PyCon DE 2011PyLucene@PyCon DE 2011
PyLucene@PyCon DE 2011
 
Tech Talk: Groovy
Tech Talk: GroovyTech Talk: Groovy
Tech Talk: Groovy
 
Ein Gopher im Netz
Ein Gopher im NetzEin Gopher im Netz
Ein Gopher im Netz
 

Slides

  • 1. Kotlin und Arrow ein Duo für FP Stefan López Romero & Felicitas Hörmann MaibornWolff GmbH 14.01.2021
  • 2. Speaker Stefan López Romero IT Architect @MaibornWolff GmbH Felicitas Hörmann So ware Engineer @MaibornWolff GmbH
  • 3. Ziel des Vortrags Vorstellung von Kotlin als funk onalere Java-Alterna ve kurzer Einblick in die bekannteste Kotlin-Library für FP: Arrow
  • 4. So leicht ist der Wechsel einfacher Ums eg für Java-Entwickler dank hoher Java-Nähe extrem hohe Interoperabilität zwischen Java und Kotlin Java-zu-Kotlin-Converter in IntelliJ enthalten problemlose Nutzung fast aller Java-Libraries möglich
  • 6. Was bietet Kotlin? viele unterstützte Einsatzbereiche objektorien erte und funk onale Komponenten prägnante Syntax (circa 40 % weniger Codezeilen als Java)
  • 7. Variablen & Typinferenz Variablen werden mit val (immutable) oder var (mutable) gekennzeichnet Typen können op onal angegeben werden val firstSpeaker = "Felicitas" val secondSpeaker: String = "Stefan" es gibt keine primi ven Typen (werden nur im Bytecode verwendet)
  • 8. Null-sichere Typen Unterscheidung zwischen nullable und non-null Referenzen Compiler erkennt, wenn eine Variable möglicherweise null ist fun main() { val nonNullable: String = "Alice" // non-nullable val nullable: String? = "Bob" // nullable println(nonNullable.length) println(nullable.length) // compiler error }
  • 9. viele Möglichkeiten zum Umgang mit nullable Referenzen (safe (?.) or non-null asserted (!!.) calls, elvis (?:), if) auch Chaining möglich val streetName = order?.customer?.address?.streetName ?: ''
  • 10. Data Classes data class Person(val name: String, val age: Int) fun main() { println(Person("Sherlock", 30)) // Person(name=Sherlock, age=30) } Automa sche Generierung von equals() toString() copy() hashcode() componentN() func ons (for destructuring)
  • 11. Extension Methods unterstützt bessere Modularisierung fun Int.addThree() = this + 3 fun main() { print(4.addThree()) // 7 }
  • 12. Lambdas & Funk onstypen Java unterstützt nur Func onal Interfaces (a.k.a. SAM) import java.util.function.Predicate; public class EvenChecker implements Predicate<Integer> { public boolean test(Integer integer) { return integer % 2 == 0; } public static void main(String[] args){ System.out.println(new EvenChecker().test(12)); } }
  • 13. Seit Java 8 können Lambdas als Implemen erung von funk onalen Interfaces verwendet werden import java.util.function.Predicate; class Main { public static void main(String[] args) { Predicate<Integer> isEven = a -> a % 2 == 0; System.out.println(isEven.test(12)); } }
  • 14. Kotlin unterstützt echte Funk onstypen und behandelt Funk onen als first class ci zens fun main() { val isEven = { a: Int -> a % 2 == 0 } println(isEven(12)) println(isEven) // (kotlin.Int) -> kotlin.Boolean } Typen können auch hier angegeben werden fun main() { val greet: (String) -> String = {name -> "Hello $name!"} println(greet("JUGHH")) // Hello JUGHH! println(greet) // (kotlin.String) -> kotlin.String }
  • 15. Higher Order Func ons & Par elle Funk onsanwendung fun main() { val greet: (getName: (Int) -> String) -> (id: Int) -> String = { getName -> { id -> "Hello ${getName(id)}!" } } val getNameForId: (Int) -> String = when(id) { 1 -> "Maria" 2 -> "Anna" else -> "Stranger" } println(greet(getNameForId)) // (kotlin.Int) -> kotlin.String println(greet(getNameForId)(1)) // Hello Maria! }
  • 16. Type Aliases erleichtert die Verwendung komplexer Typen typealias Predicate<T> = (T) -> Boolean
  • 17. Aggregate Opera ons in Java mit Hilfe von Streams möglich import java.util.*; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); List<Integer> doubledList = list .stream() .map(n -> 2 - n) .collect(Collectors.toList()); System.out.println(doubledList); // [2, 4, 6, 8, 10] } }
  • 18. in Kotlin straigh orward fun main() { val list: List<Int> = listOf(1, 2, 3, 4, 5); // trailing lambda // it für single lambda parameter val doubledList = list.map { it - 2 } val gaussianSum = (1..100).toList().reduce(Int::plus) } min(), max(), average(), sum() & Versionen mit explizitem Comparator fold(), reduce() (beide le ) & right-, indexed- und "orNull"-Versionen
  • 19. Was fehlt Kotlin? Sprach-Features Higher Kinded Types Typ-Klassen Library-Features Funk onen zur Komposi on und für (Un-)Currying Funk onale Datentypen (Op on, Either etc.) Abstrak onen (Funktoren, Monaden etc.)
  • 21. Was ist Arrow Stdlib für FP in Kotlin Fusion aus KATEGORY und funKTionale Erstes Release 2018 Thoughtworks Tech Radar: Kategorie Adopt
  • 22. Was bietet Arrow Arrow-Core: Funk onale Std-Lib (Basis) Basis Funk onen ( compose , curry ...) Funk onale Datentypen ( Option , Either ...) Emula on: Higher Kinded Types Typ-Klassen Arrow-Fx: Seiteneffekte funk onal handhaben Arrow-Op cs: Transforma on von immutable Daten
  • 23. Basis Funk onen in Arrow
  • 24. Funk onskomposi on Funk onskomposi on ist das Mi el um größere Programme durch Kombina on von einzelnen Funk onen zu schreiben. Seien A, B, C beliebige Mengen und g: A ➝ B sowie f: B ➝ C Funk onen, so heißt die Funk on f ° g : A ➝ C , (f ° g)(x) = f(g(x)) Komposi on von f und g
  • 25. Funk onskomposi on mit Arrow Arrow bietet hierfür die Funk onen compose , andThen , forwardCompose val parse: (String) -> Int = { it.toInt()} val addOne: (Int) -> Int = { it + 1 } val parseAddOne1: (String) -> Int = addOne.compose(parse) val result = parseAddOne1("5") // = 6 ≙ addOne(parse("5")) val parseAddOne2: (String) -> Int = parse.andThen(addOne) val parseAddOne3: (String) -> Int = parse.forwardCompose(addOne)
  • 26. Currying Currying ist die Umwandlung einer Funk on mit mehreren Argumenten in eine gleichwer ge Sequenz von Funk onen mit jeweils einem Argument. fun <A, B, C> ((A, B)-> C).curry() : (A) -> ((B) -> C) = { a -> { b -> this(a, b)} }
  • 27. Currying mit Arrow Arrow bietet hierfür die Funk onen curry und uncurry val calcTax: (Double, Double) -> Double = { value, rate -> value - rate } val calcTaxCurried: (Double) -> (Double) -> Double = calcTax.curried() val calcVat = calcTaxCurried(0.19) val vat = calcVat(149.99) val vat2 = calcTaxCurried.uncurried()(0.19, 149.99)
  • 28. Par elle Funk onsanwendung Arrow bietet hierfür die Funk onen partially2 bis partially22 val calcTaxForRate: (Double) -> Double = calcTax.partially2(149.99); val reducedVat = calcTaxForRate(0.07); val Vat = calcTaxForRate(0.19);
  • 30. Eine Auswahl Option Either ListK , SetK , MapK NonEmptyList ...
  • 32. Typklassen als höhere Abstrak onen Design-Pa erns der Funk onalen Programmierung Keine Klassen im OOP Sinne Eher wie Interfaces auf sehr abstrakter Ebene Besteht aus Algebra ≙ Funk onen und Gesetze ≙ Verhalten
  • 33. Die Funk on map //List var l: List<Int> = listOf("1", "2", "3", "4").map { it.toInt() } //Option var o:Option<Int> = Some("1").map { it.toInt() } Die Signatur von map //List fun <A, B> List<A>.map(f: (A) -> B): List<B> //Option fun <A, B> Option<A>.map(f: (A) -> B): Option<B>
  • 34. Typklasse Functor interface Functor<F> { fun <A, B> F<A>.map(f: (A) -> B): F<B> } F<A> was ist das?
  • 35. Higher kinded Types mit Arrow Mit dem Interface Kind lässt sich unser Problem lösen interface Kind<out F, out A> interface Functor<F> { fun <A, B> Kind<F, A>.map(f: (A) -> B): Kind<F, B> }
  • 36. Datentyp für op onale Werte @higherkind sealed class Option<out A> : Kind<ForOption, A> { companion object } data class Some<out A>(val get: A) : Option<A>() object None : Option<Nothing>()
  • 37. Arrow generiert helper ForOption als Ersatztyp für Option<A> ohne den generischen Typ-Parameter. Es wird sichergestellt, dass Option<A> die einzige Implemen erung von Kind<ForOption, A> ist. fix Funk on zur Umwandlung von Kind<ForOption, A> zu Option<A> Option<A> zu Kind<ForOption, A> via subclassing
  • 38. Funktor für Option @extension interface OptionFunctor : Functor<ForOption> { override fun <A, B> Kind<ForOption, A>.map(f: (A) -> B): Option<B> { val option : Option<A> = this.fix() return when(option) { is None -> None is Some -> Some(f(option.get)) } } } @extension : generiert ein Objekt aus dem interface mit allen bereits definierten default-methoden erweitert das companion object von Option um eine Funk on functor() , die das Objekt zurückgibt
  • 39. Anwendungsbeispiel fun <F> abs(fa: Kind<F, Int>, FT: Functor<F>) : Kind<F, Int> = FT.run { fa.map { when { it < 0 -> - it else -> it } } } val res1 = abs(LinkedList(1,-2, -3), LinkedList.functor()).fix() // [1, 2, 3] val res2 = abs(Some(-2), Option.functor()).fix() // 2
  • 40. Iden tät eines Funktors Abbildung auf sich selbst ≙ unveränderter Funktor fun <F, A> identity(fa: Kind<F, A>, FT: Functor<F> ) : Boolean = FT.run { fa.map { it } == fa }
  • 41. Assozia vität eines Funktors Mehrere map Funk onen nacheinander ≙ Komposi on beider map Funk onen fun <F, A, B, C> associativity(fa: Kind<F, A>, FT: Functor<F>, f: (A)-> B, g:(B) -> C) : Boolean = FT.run { fa.map(f).map(g) == fa.map(f.andThen(g)) }
  • 42. Sind die Gesetze erfüllt? assert(identity(Some(3), Option.functor())) val parseInt : (String) -> Int = { s -> Integer.parseInt(s)} val plusOne : (Int) -> Int = { x:Int -> x.plus(1)} assert(associativity(Some("1"), Option.functor(), parseInt, plusOne))
  • 43. Unser Eindruck Arrow ist ein gut strukturierter Baukasten Advanced FP ist auch mit Kotlin möglich Simula on von Higher Kinded Types etwas gewöhnungsbedür ig Code-Generierung macht manchmal Probleme Im Projekt definieren, was aus dem Baukasten verwendet werden darf/soll.
  • 44. Ich will mehr davon Func onal Programming in Kotlin - Manning Kotlin Koans - zum Kennenlernen von Kotlin