SlideShare une entreprise Scribd logo
1  sur  70
training@instil.co
May 2018
© Instil Software 2018
The Arrow Library in Kotlin
Cork JUG / Functional Programmers
https://gitlab.com/instil-training/cjug-arrow-2018
Thank You Kats & JUGs For Inviting Me Once Again!
A quick Kotlin refresher
• Kotlin compared to Java
• Functional coding in Kotlin
• Reactive Programming in Kotlin
Introducing Arrow
• What is it and why does it matter?
Arrow Pt1: Data Types
• Option, Try, Either and Validated
Arrow Pt2: Enhanced FP
• Partial Invocation, Currying and Composition
Arrow Pt3: Esoteric Stuff
• Lenses, IO etc…
Agenda For This Talk
• In case this is all new to you…
Kotlin Refresher
Kotlin Compared To Java
Enter some numbers or three 'X' to finish
10
20
30
40
50
XXX
Total of numbers is: 150
Enter some numbers or three 'X' to finish
wibble
Ignoring wibble
12
13
14
XXX
Total of numbers is: 39
Enter some numbers or three 'X' to finish
XXX
Total of numbers is: 0
public class Program {
public static void main(String[] args) {
@SuppressWarnings("resource")
Scanner scanner = new Scanner(System.in);
List<Integer> numbers = new ArrayList<>();
System.out.println("Enter some numbers or three 'X' to finish");
Pattern endOfInput = Pattern.compile("[X]{3}");
while(scanner.hasNextLine()) {
if(scanner.hasNextInt()) {
numbers.add(scanner.nextInt());
} else {
if(scanner.hasNext(endOfInput)) {
break;
} else {
String mysteryText = scanner.nextLine();
System.out.printf(“Ignoring %sn", mysteryText);
}
}
}
int total = numbers.stream().reduce((a,b) -> a + b).orElse(0);
System.out.printf("Total of numbers is: %sn",total);
}
}
A Sample Java Program
fun main(args: Array<String>) {
val numbers = mutableListOf<Int>()
val scanner = Scanner(System.`in`)
val endOfInput = Regex("[X]{3}")
println("Enter some numbers or three 'X' to finish")
while (scanner.hasNextLine()) {
if (scanner.hasNextInt()) {
numbers += scanner.nextInt()
} else {
if (scanner.hasNext(endOfInput.toPattern())) {
break
} else {
val mysteryText = scanner.nextLine()
println("Ignoring $mysteryText")
}
}
}
val total1 = numbers.fold(0,Int::plus)
println("Total of numbers is: $total1")
//simpler alternative in this case
val total2 = numbers.sum()
println("Total of numbers is: $total2")
}
The Sample Re-Written in Kotlin
Points to note:
 No redundant class
 No semi-colons
 Type inference
 Both ‘val’ and ‘var’
 Helper functions
 String interpolation
 Simplified collections
 Interop with Java types
 Simpler use of FP
Functional Programming
fun <T,U>map(input: List<T>, mappingFunc: (T)->U): List<U> {
val results = ArrayList<U>()
for (item in input) {
results.add(mappingFunc(item));
}
return results
}
fun <T>filter(input: List<T>, filterFunc: (T)->Boolean): List<T> {
val results = ArrayList<T>()
for (item in input) {
if (filterFunc(item)) {
results.add(item);
}
}
return results
}
fun <T>partition(input: List<T>, filterFunc: (T)->Boolean): Pair<List<T>,List<T>> {
val results = Pair(ArrayList<T>(),ArrayList<T>())
for (item in input) {
if (filterFunc(item)) {
results.first.add(item);
} else {
results.second.add(item);
}
}
return results
}
Implementing Filter, Map and Partition
fun main(args: Array<String>) {
val originalData = arrayListOf<String>("12","34","56","78","90")
val mappedData = map(originalData, String::toInt)
val filteredData = filter(mappedData) { it > 50 }
val partitionedData = partition(mappedData) { it > 50 }
printResults("Results of mapping",mappedData)
printResults("Results of filtering", filteredData)
printResults("Results of partitioning", partitionedData)
}
fun<T> printResults(title: String, input: List<T>) {
println("----- $title -----")
for(item in input) {
println("t$item")
}
}
fun<T,U> printResults(title: String, input: Pair<List<T>,List<U>>) {
println("----- $title -----")
println("tfirst items in pair")
for(item in input.first) {
println("tt$item")
}
println("tsecond items in pair")
for(item in input.second) {
println("tt$item")
}
}
Implementing Filter, Map and Partition
Implementing Filter, Map and Partition
----- Results of mapping -----
12
34
56
78
90
----- Results of filtering -----
56
78
90
----- Results of partitioning -----
first items in pair
56
78
90
second items in pair
12
34
fun wrapInH1(input: String) = "<h1>$input</h1>"
fun wrapInH2(input: String) = "<h2>$input</h2>"
fun wrapInTag(tagName: String, input: String): String {
val openingTag = "<$tagName>"
val closingTag = "</$tagName>"
return "$openingTag$input$closingTag"
}
fun buildWrapper(tagName: String): (String) -> String {
val openingTag = "<$tagName>"
val closingTag = "</$tagName>"
return { "$openingTag$it$closingTag" }
}
Using Functions as Outputs
fun main(args: Array<String>) {
println(wrapInH1("Marge"))
println(wrapInH2("Homer"))
println(wrapInTag("h3","Liza"))
println(wrapInTag("h4","Bart"))
val wrapInBold = buildWrapper("b")
val wrapInItalics = buildWrapper("i")
val wrapInMark = buildWrapper("mark")
println(wrapInBold("Maggie"))
println(wrapInItalics("Snowball III"))
println(wrapInMark("Santas Little Helper"))
}
<h1>Marge</h1>
<h2>Homer</h2>
<h3>Liza</h3>
<h4>Bart</h4>
<b>Maggie</b>
<i>Snowball III</i>
<mark>Santas Little Helper</mark>
Using Functions as Outputs
Reactive Programming
fun main(args: Array<String>) {
val loremIpsum = """Lorem ipsum dolor sit amet, consectetur adipiscing
elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip
ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore
eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum."""
val flux = Flux.fromIterable(loremIpsum.split(" "))
flux.map { it.toLowerCase() }
.flatMap { word -> Flux.fromArray(word.toCharArray()
.toTypedArray()) }
.filter { theChar -> Character.isLetter(theChar) }
.collectMultimap { it }
.map { table -> table.mapValues { entry -> entry.value.size } }
.subscribe(::printTable)
}
Using Project Reactor To Process In-Memory Data
fun printTable(input: Map<Char, Int>) {
println("The frequency count of letters in 'lorem ipsum' is:")
input.forEach { entry ->
val msgWord = "instance" + if (entry.value > 1) "s" else ""
println("${entry.value} $msgWord of ${entry.key}")
}
}
The frequency count of letters in 'lorem ipsum' is:
29 instances of a
3 instances of b
16 instances of c
19 instances of d
38 instances of e
3 instances of f
3 instances of g
1 instance of h
42 instances of i
22 instances of l
17 instances of m
24 instances of n
29 instances of o
11 instances of p
...
Using Reactor To Process In-Memory Data
• What is it?
• Why does it matter?
Introducing Arrow
Languages Today Are Converging
The Great Scala vs. Kotlin Debate
I am an Enterprise
Coder. Like my father
before me
You fool. If only you
knew the power of
Monads!
How Much Functional Programming is ‘Just Right’?
One Possible Solution…
Arrow is a functional programming library for Kotlin coders
• Launched in Jan when the two leading libraries joined focus
• To prevent the ‘Scalaz vs. Cats’ debate that exists in Scala
It is not a formal part of the Kotlin environment
• But is generating a lot of interest in the Kotlin community
• It has resulted in proposals for changes to the language
Learning Arrow can be a bit frustrating as:
• The documentation is incomplete and patchy
• Changes are still occurring between releases
• Sample code is hard to find….
I’m still learning what its all about!
• This is very much a report on my progress so far…
Introducing Arrow
Part One: Data Types
Lets Do The Same Thing Many Times 
Option
fun readPropertyA(name: String): Option<String> {
val result = System.getProperty(name)
return if(result != null) Some(result) else None
}
fun readPropertyB(name: String) =
Option.fromNullable(System.getProperty(name))
Reading Property Values Safely Via Option
fun print1(input: Option<String>): Unit {
when(input) {
is None -> println("Nothing was found")
is Some -> println("'${input.t}' was found")
}
}
fun print2(input: Option<String>): Unit {
println("${input.getOrElse { "Nothing" }} was found")
}
Reading Property Values Safely Via Option
fun print3(input: Option<String>): Unit {
val result = input.fold({ "Nothing" }, { it })
println("$result was found")
}
fun print4(input1: Option<String>, input2: Option<String>): Unit {
val result = input1.flatMap { first ->
input2.map { second ->
"$first and $second"
}
}
println("Results are ${result.getOrElse { "Nothing" }}")
}
Reading Property Values Safely Via Option
fun main(args: Array<String>) {
print1(readPropertyA("java.version"))
print1(readPropertyA("wibble"))
printLine()
print2(readPropertyB("java.version"))
print2(readPropertyB("wibble"))
printLine()
print3(readPropertyA("java.version"))
print3(readPropertyA("wibble"))
printLine()
print4(
readPropertyA("java.version"),
readPropertyB("java.version")
)
printLine()
print4(
readPropertyA("java.version"),
readPropertyB("wibble")
)
printLine()
print4(readPropertyA("wibble"), readPropertyB("wibble"))
printLine()
print4(readPropertyA("wibble"), readPropertyB("wibble"))
}
Reading Property Values Safely Via Option
Reading Property Values Safely Via Option
'1.8.0_121' was found
Nothing was found
---------------
1.8.0_121 was found
Nothing was found
---------------
1.8.0_121 was found
Nothing was found
---------------
Results are 1.8.0_121 and 1.8.0_121
---------------
Results are Nothing
---------------
Results are Nothing
---------------
Results are Nothing
class Postcode(val input: String?) {
fun value() = Option.fromNullable(input)
}
class Address(val street: String, val postcode: Postcode?) {
fun location() = Option.fromNullable(postcode)
}
class Person(val name: String, val address: Address?) {
fun residence() = Option.fromNullable(address)
}
Using Option as a Monad
fun printPostcode(person: Person) {
val result = Option.monad().binding {
val address = person.residence().bind()
val location = address.location().bind()
location.value().bind()
}.fix()
println(result.fold( { "No postcode available" },
{ "Postcode of $it" }))
}
Using Option as a Monad
fun main(args: Array<String>) {
printPostcode(Person("Dave",
Address("10 Arcatia Road",
Postcode("ABC 123"))))
printPostcode(Person("Dave",
Address("10 Arcatia Road", null)))
printPostcode(Person("Dave", null))
}
Using Option as a Monad
Postcode of ABC 123
No postcode available
No postcode available
Try
fun firstLine(path: String): Try<String> {
fun readFirstLine(path: String): String {
val reader = BufferedReader(FileReader(path))
return reader.use { it.readLine() }
}
return Try { readFirstLine(path) }
}
Reading the First Line from a File via Try
fun print1(input: Try<String>): Unit {
when(input) {
is Success -> println("Read '${input.value}'")
is Failure -> println("Threw '${input.exception.message}'")
}
}
fun print2(input: Try<String>): Unit {
val result = input.fold( { "Threw '${it.message}'" },
{ "Read '$it'" })
println(result)
}
fun print3(input: Try<String>): Unit {
input.map { println("Read '$it'") }
input.recover { println("Threw '${it.message}'") }
}
Reading the First Line from a File via Try
Lets Have Some Fun 
fun print4(input: String) {
fun fullPath(str: String) = "data/$str"
val finalResult = firstLine(fullPath(input)).flatMap { one ->
firstLine(fullPath(one)).flatMap { two ->
firstLine(fullPath(two)).flatMap { three ->
firstLine(fullPath(three)).flatMap { four ->
firstLine(fullPath(four)).map { result ->
result
}
}
}
}
}
val message = finalResult.fold({ it.message }, { it })
println("Path navigation produced '$message'")
}
Reading the First Line from a File via Try
fun main(args: Array<String>) {
print1(firstLine("data/input4.txt"))
print1(firstLine("foobar.txt"))
printLine()
print2(firstLine("data/input4.txt"))
print2(firstLine("foobar.txt"))
printLine()
print3(firstLine("data/input4.txt"))
print3(firstLine("foobar.txt"))
printLine()
print4("input.txt")
print4("foobar.txt")
}
Reading the First Line from a File via Try
Read 'Fortune favors the prepared mind'
Threw 'foobar.txt (No such file or directory)'
---------------
Read 'Fortune favors the prepared mind'
Threw 'foobar.txt (No such file or directory)'
---------------
Read 'Fortune favors the prepared mind'
Threw 'foobar.txt (No such file or directory)'
---------------
Path navigation produced 'Fortune favors the prepared mind'
Path navigation produced 'data/foobar.txt (No such file or directory)'
fun readFromFiles(input: String): String? {
val result = Try.monad().binding {
val one = firstLine(fullPath(input)).bind()
val two = firstLine(fullPath(one)).bind()
val three = firstLine(fullPath(two)).bind()
val four = firstLine(fullPath(three)).bind()
firstLine(fullPath(four)).bind()
}.fix()
return result.fold({ it.message }, { it })
}
Reading the First Line from a File via Try
fun main(args: Array<String>) {
println("Path navigation produced '${readFromFiles("input.txt")}'")
println("Path navigation produced '${readFromFiles("foobar")}'")
}
Path navigation produced 'Fortune favors the prepared mind'
Path navigation produced 'data/foobar (No such file or directory)'
Either
fun genNumber() : Either<Int, Int> {
val number = (random() * 100).toInt()
return if(number % 2 == 0) Right(number) else Left(number)
}
fun main(args: Array<String>) {
val results = (1 .. 10).map {
genNumber().flatMap { first ->
genNumber().map { second ->
Pair(first, second)
}
}
}
results.forEach { result ->
val msg = result.fold(
{ "Odd number $it" },
{ "Even numbers ${it.first} and ${it.second}" }
)
println(msg)
}
}
Using the Either Type
Even numbers 50 and 40
Odd number 77
Even numbers 52 and 32
Odd number 25
Odd number 89
Even numbers 80 and 54
Odd number 65
Odd number 1
Odd number 1
Odd number 33
Validated
Our Sample Problem
Whats your ID?
ab12
How old are you?
19
Where do you work?
HR
Error: Bad ID
Whats your ID?
AB12
How old are you?
19
Where do you work?
IT
Result: AB12 of age 19 working in IT
Whats your ID?
ab12
How old are you?
14
Where do you work?
Mars
Error: Bad Dept Bad ID Bad Age
class Employee(val id: String, val age: Int, val dept: String) {
override fun toString() = "$id of age $age working in $dept"
}
fun askQuestion(question: String): String {
println(question)
return readLine() ?: ""
}
Reading and Validating Information
fun checkID(): Validated<String, String> {
val regex = Regex("[A-Z]{2}[0-9]{2}")
val response = askQuestion("Whats your ID?")
return if(regex.matches(response)) Valid(response)
else Invalid("Bad ID")
}
fun checkAge(): Validated<String, Int> {
val response = askQuestion("How old are you?").toInt()
return if(response > 16) Valid(response) else Invalid("Bad Age")
}
fun checkDept(): Validated<String, String> {
val depts = listOf("HR", "Sales", "IT")
val response = askQuestion("Where do you work?")
return if(depts.contains(response)) Valid(response)
else Invalid("Bad Dept")
}
Reading and Validating Information
fun main(args: Array<String>) {
val sg = object : Semigroup<String> {
override fun String.combine(b: String) = "$this $b"
}
val id = checkID()
val age = checkAge()
val dept = checkDept()
val result = Validated.applicative(sg)
.map(id, age, dept, {
(a,b,c) -> Employee(a,b,c)
})
.fix()
println(result.fold({ "Error: $it" }, {"Result: $it"} ))
}
Reading and Validating Information
Part Two: Functions
Lets Play With Plugging Functions Together…
Partial Invocation
fun demo1() {
val addNums = { no1: Int, no2: Int ->
println("Adding $no1 to $no2")
no1 + no2
}
val addSeven = addNums.partially2(7)
val result = addSeven(3)
println(result)
}
Partial Invocation
Adding 3 to 7
10
fun demo2() {
val addNums = { no1: Int, no2: Int ->
println("Adding $no1 to $no2")
no1 + no2
}
val addSeven = addNums.partially2(7)
val addSevenToThree = addSeven.partially1(3)
val result = addSevenToThree()
println(result)
}
Partial Invocation
Adding 3 to 7
10
fun demo3() {
val addNums = { no1: Int, no2: Int ->
println("Adding $no1 to $no2")
no1 + no2
}
val addSeven = addNums.reverse().partially2(7)
val result = addSeven(3)
println(result)
}
Partial Invocation
Adding 7 to 3
10
fun grep(path: String, regex: Regex, action: (String) -> Unit) {
val reader = BufferedReader(FileReader(path))
reader.use {
it.lines()
.filter { regex.matches(it) }
.forEach(action)
}
}
val grepLambda = { a: String, b: Regex, c: (String) -> Unit ->
grep(a, b, c)
}
fun printLine() = println("-------------")
Here’s Something More Useful
val filePath = "data/grepInput.txt"
val regex = "[A-Z]{2}[0-9]{2}".toRegex()
grep(filePath, regex, ::println)
printLine()
grepLambda(filePath, regex, ::println)
printLine()
Here’s Something More Useful
AB12
CD34
EF56
-------------
AB12
CD34
EF56
-------------
val grepAndPrint = grepLambda.partially3(::println)
grepAndPrint(filePath, regex)
printLine()
val sb = StringBuilder()
val grepAndConcat = grepLambda.partially3 {sb.append(it)}
grepAndConcat(filePath, regex)
println(sb.toString())
printLine()
val grepAndPrintRegex = grepAndPrint.partially2(regex)
grepAndPrintRegex(filePath)
Here’s Something More Useful
AB12
CD34
EF56
-------------
AB12CD34EF56
-------------
AB12
CD34
EF56
Currying
val addThree = { a:Int, b: Int, c:Int ->
println("Adding $a, $b and $c")
a + b + c
}
fun printLine() = println("--------------------")
fun main(args: Array<String>) {
println(addThree(10,20,40))
printLine()
val f1 = addThree.curried()
val f2 = f1(10)
val f3 = f2(20)
val result = f3(40)
println(result)
printLine()
println(f1(10)(20)(40))
printLine()
val f4 = addThree.reverse().curried()
println(f4(10)(20)(40))
println()
}
The Basic Syntax of Currying
Adding 10, 20 and 40
70
--------------------
Adding 10, 20 and 40
70
--------------------
Adding 10, 20 and 40
70
--------------------
Adding 40, 20 and 10
70
fun grep(path: String, regex: Regex, action: (String) -> Unit) {
val reader = BufferedReader(FileReader(path))
reader.use {
it.lines()
.filter { regex.matches(it) }
.forEach(action)
}
}
val grepLambda = { a: String, b: Regex, c: (String) -> Unit ->
grep(a,b,c) }
fun printLine() = println("-------------")
A More Useful Example
fun main(args: Array<String>) {
val filePath = "data/grepInput.txt"
val regex1 = "[A-Z]{2}[0-9]{2}".toRegex()
val regex2 = "[a-z]{2}[0-9]{2}".toRegex()
val f1 = grepLambda.curried()
val grepInFile = f1(filePath)
val grepRegex1 = grepInFile(regex1)
val grepRegex2 = grepInFile(regex2)
grepRegex1(::println)
printLine()
grepRegex2(::println)
}
A More Useful Example
AB12
CD34
EF56
-------------
ab12
cd34
ef56
Composition
val source = { name: String -> "data/$name" }
val allLines = { path: String ->
val reader = BufferedReader(FileReader(path))
reader.use {
it.lines().toList()
}
}
val findMatches = { input: List<String> ->
val regex = "[A-Z]{2}[0-9]{2}".toRegex()
input.filter(regex::matches)
}
Composing Functions Together
fun main(args: Array<String>) {
val composed1 = findMatches compose allLines compose source
println(composed1("grepInput.txt"))
val composed2 = source forwardCompose allLines forwardCompose findMatches
println(composed2("grepInput.txt"))
val composed3 = source andThen allLines andThen findMatches
println(composed3("grepInput.txt"))
}
Composing Functions Together
[AB12, CD34, EF56]
[AB12, CD34, EF56]
[AB12, CD34, EF56]
Part 3: Weird Stuff
Lenses
@optics
data class Postcode(val value: String) {
override fun toString() = "$value"
}
@optics
data class Address(val street: String, val postcode: Postcode) {
override fun toString() = "$street ($postcode)"
}
@optics
data class Person(val name: String, val address: Address) {
override fun toString() = "$name living at $address"
}
Copying Immutable Structures With Lenses
fun main(args: Array<String>) {
val oldPerson = Person("Dave",
Address("10 Arcatia Road",
Postcode("BT26 ABC")))
println(oldPerson)
val personAddressPostcode
= personAddress() compose addressPostcode() compose postcodeValue()
val newPerson
= personAddressPostcode.modify(oldPerson, { _ -> "BT37 DEF" })
println(newPerson)
}
Copying Immutable Structures With Lenses
Dave living at 10 Arcatia Road (BT26 ABC)
Dave living at 10 Arcatia Road (BT37 DEF)

Contenu connexe

Tendances

PYTHON -Chapter 2 - Functions, Exception, Modules and Files -MAULIK BOR...
PYTHON -Chapter 2 - Functions,   Exception, Modules  and    Files -MAULIK BOR...PYTHON -Chapter 2 - Functions,   Exception, Modules  and    Files -MAULIK BOR...
PYTHON -Chapter 2 - Functions, Exception, Modules and Files -MAULIK BOR...
Maulik Borsaniya
 
Python Performance 101
Python Performance 101Python Performance 101
Python Performance 101
Ankur Gupta
 

Tendances (20)

PYTHON -Chapter 2 - Functions, Exception, Modules and Files -MAULIK BOR...
PYTHON -Chapter 2 - Functions,   Exception, Modules  and    Files -MAULIK BOR...PYTHON -Chapter 2 - Functions,   Exception, Modules  and    Files -MAULIK BOR...
PYTHON -Chapter 2 - Functions, Exception, Modules and Files -MAULIK BOR...
 
Introduction to Python - Part Two
Introduction to Python - Part TwoIntroduction to Python - Part Two
Introduction to Python - Part Two
 
Python Basics
Python BasicsPython Basics
Python Basics
 
Chapter 5 - THREADING & REGULAR exp - MAULIK BORSANIYA
Chapter 5 - THREADING & REGULAR exp - MAULIK BORSANIYAChapter 5 - THREADING & REGULAR exp - MAULIK BORSANIYA
Chapter 5 - THREADING & REGULAR exp - MAULIK BORSANIYA
 
Basic Python Programming: Part 01 and Part 02
Basic Python Programming: Part 01 and Part 02Basic Python Programming: Part 01 and Part 02
Basic Python Programming: Part 01 and Part 02
 
Programming in Python
Programming in Python Programming in Python
Programming in Python
 
Python basics
Python basicsPython basics
Python basics
 
EuroPython 2016 - Do I Need To Switch To Golang
EuroPython 2016 - Do I Need To Switch To GolangEuroPython 2016 - Do I Need To Switch To Golang
EuroPython 2016 - Do I Need To Switch To Golang
 
Introduction to Kotlin
Introduction to KotlinIntroduction to Kotlin
Introduction to Kotlin
 
PPT on Data Science Using Python
PPT on Data Science Using PythonPPT on Data Science Using Python
PPT on Data Science Using Python
 
Python Performance 101
Python Performance 101Python Performance 101
Python Performance 101
 
python.ppt
python.pptpython.ppt
python.ppt
 
Kotlin Bytecode Generation and Runtime Performance
Kotlin Bytecode Generation and Runtime PerformanceKotlin Bytecode Generation and Runtime Performance
Kotlin Bytecode Generation and Runtime Performance
 
Basics of Python programming (part 2)
Basics of Python programming (part 2)Basics of Python programming (part 2)
Basics of Python programming (part 2)
 
Euro python2011 High Performance Python
Euro python2011 High Performance PythonEuro python2011 High Performance Python
Euro python2011 High Performance Python
 
Comparing JVM languages
Comparing JVM languagesComparing JVM languages
Comparing JVM languages
 
Python
PythonPython
Python
 
Odessapy2013 - Graph databases and Python
Odessapy2013 - Graph databases and PythonOdessapy2013 - Graph databases and Python
Odessapy2013 - Graph databases and Python
 
SQL Server Select Topics
SQL Server Select TopicsSQL Server Select Topics
SQL Server Select Topics
 
python codes
python codespython codes
python codes
 

Similaire à The Arrow Library in Kotlin

The Kotlin Programming Language
The Kotlin Programming LanguageThe Kotlin Programming Language
The Kotlin Programming Language
intelliyole
 
Create a menu-driven program that will accept a collection of non-ne.pdf
Create a menu-driven program that will accept a collection of non-ne.pdfCreate a menu-driven program that will accept a collection of non-ne.pdf
Create a menu-driven program that will accept a collection of non-ne.pdf
rajeshjangid1865
 

Similaire à The Arrow Library in Kotlin (20)

The Kotlin Programming Language
The Kotlin Programming LanguageThe Kotlin Programming Language
The Kotlin Programming Language
 
Functions In Scala
Functions In Scala Functions In Scala
Functions In Scala
 
Kotlin @ Devoxx 2011
Kotlin @ Devoxx 2011Kotlin @ Devoxx 2011
Kotlin @ Devoxx 2011
 
Mixing functional programming approaches in an object oriented language
Mixing functional programming approaches in an object oriented languageMixing functional programming approaches in an object oriented language
Mixing functional programming approaches in an object oriented language
 
Arrow 101 - Kotlin funcional com Arrow
Arrow 101 - Kotlin funcional com ArrowArrow 101 - Kotlin funcional com Arrow
Arrow 101 - Kotlin funcional com Arrow
 
Scala introduction
Scala introductionScala introduction
Scala introduction
 
Cocoaheads Meetup / Alex Zimin / Swift magic
Cocoaheads Meetup / Alex Zimin / Swift magicCocoaheads Meetup / Alex Zimin / Swift magic
Cocoaheads Meetup / Alex Zimin / Swift magic
 
Александр Зимин (Alexander Zimin) — Магия Swift
Александр Зимин (Alexander Zimin) — Магия SwiftАлександр Зимин (Alexander Zimin) — Магия Swift
Александр Зимин (Alexander Zimin) — Магия Swift
 
Arrays
ArraysArrays
Arrays
 
Functional programming in C++
Functional programming in C++Functional programming in C++
Functional programming in C++
 
Functional Programming You Already Know - Kevlin Henney - Codemotion Rome 2015
Functional Programming You Already Know - Kevlin Henney - Codemotion Rome 2015Functional Programming You Already Know - Kevlin Henney - Codemotion Rome 2015
Functional Programming You Already Know - Kevlin Henney - Codemotion Rome 2015
 
TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de pro...
TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de pro...TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de pro...
TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de pro...
 
Functional programming ii
Functional programming iiFunctional programming ii
Functional programming ii
 
Create a menu-driven program that will accept a collection of non-ne.pdf
Create a menu-driven program that will accept a collection of non-ne.pdfCreate a menu-driven program that will accept a collection of non-ne.pdf
Create a menu-driven program that will accept a collection of non-ne.pdf
 
Advanced Web Technology ass.pdf
Advanced Web Technology ass.pdfAdvanced Web Technology ass.pdf
Advanced Web Technology ass.pdf
 
Functional Programming in Swift
Functional Programming in SwiftFunctional Programming in Swift
Functional Programming in Swift
 
Rethink programming: a functional approach
Rethink programming: a functional approachRethink programming: a functional approach
Rethink programming: a functional approach
 
Taming Asynchronous Transforms with Interstellar
Taming Asynchronous Transforms with InterstellarTaming Asynchronous Transforms with Interstellar
Taming Asynchronous Transforms with Interstellar
 
Scala en
Scala enScala en
Scala en
 
Functional concepts in C#
Functional concepts in C#Functional concepts in C#
Functional concepts in C#
 

Plus de Garth Gilmour

Plus de Garth Gilmour (20)

Compose in Theory
Compose in TheoryCompose in Theory
Compose in Theory
 
Kotlin / Android Update
Kotlin / Android UpdateKotlin / Android Update
Kotlin / Android Update
 
TypeScript Vs. KotlinJS
TypeScript Vs. KotlinJSTypeScript Vs. KotlinJS
TypeScript Vs. KotlinJS
 
Shut Up And Eat Your Veg
Shut Up And Eat Your VegShut Up And Eat Your Veg
Shut Up And Eat Your Veg
 
Lies Told By The Kotlin Compiler
Lies Told By The Kotlin CompilerLies Told By The Kotlin Compiler
Lies Told By The Kotlin Compiler
 
A TypeScript Fans KotlinJS Adventures
A TypeScript Fans KotlinJS AdventuresA TypeScript Fans KotlinJS Adventures
A TypeScript Fans KotlinJS Adventures
 
The Heat Death Of Enterprise IT
The Heat Death Of Enterprise ITThe Heat Death Of Enterprise IT
The Heat Death Of Enterprise IT
 
Lies Told By The Kotlin Compiler
Lies Told By The Kotlin CompilerLies Told By The Kotlin Compiler
Lies Told By The Kotlin Compiler
 
Type Driven Development with TypeScript
Type Driven Development with TypeScriptType Driven Development with TypeScript
Type Driven Development with TypeScript
 
Generics On The JVM (What you don't know will hurt you)
Generics On The JVM (What you don't know will hurt you)Generics On The JVM (What you don't know will hurt you)
Generics On The JVM (What you don't know will hurt you)
 
Using Kotlin, to Create Kotlin, to Teach Kotlin, in Space
Using Kotlin, to Create Kotlin,to Teach Kotlin,in SpaceUsing Kotlin, to Create Kotlin,to Teach Kotlin,in Space
Using Kotlin, to Create Kotlin, to Teach Kotlin, in Space
 
Is Software Engineering A Profession?
Is Software Engineering A Profession?Is Software Engineering A Profession?
Is Software Engineering A Profession?
 
Social Distancing is not Behaving Distantly
Social Distancing is not Behaving DistantlySocial Distancing is not Behaving Distantly
Social Distancing is not Behaving Distantly
 
The Great Scala Makeover
The Great Scala MakeoverThe Great Scala Makeover
The Great Scala Makeover
 
Transitioning Android Teams Into Kotlin
Transitioning Android Teams Into KotlinTransitioning Android Teams Into Kotlin
Transitioning Android Teams Into Kotlin
 
Simpler and Safer Java Types (via the Vavr and Lambda Libraries)
Simpler and Safer Java Types (via the Vavr and Lambda Libraries)Simpler and Safer Java Types (via the Vavr and Lambda Libraries)
Simpler and Safer Java Types (via the Vavr and Lambda Libraries)
 
The Three Horse Race
The Three Horse RaceThe Three Horse Race
The Three Horse Race
 
The Bestiary of Pure Functional Programming
The Bestiary of Pure Functional Programming The Bestiary of Pure Functional Programming
The Bestiary of Pure Functional Programming
 
BelTech 2019 Presenters Workshop
BelTech 2019 Presenters WorkshopBelTech 2019 Presenters Workshop
BelTech 2019 Presenters Workshop
 
Kotlin The Whole Damn Family
Kotlin The Whole Damn FamilyKotlin The Whole Damn Family
Kotlin The Whole Damn Family
 

Dernier

CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
shinachiaurasa2
 

Dernier (20)

Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verifiedSector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdfAzure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 

The Arrow Library in Kotlin

  • 1. training@instil.co May 2018 © Instil Software 2018 The Arrow Library in Kotlin Cork JUG / Functional Programmers https://gitlab.com/instil-training/cjug-arrow-2018
  • 2. Thank You Kats & JUGs For Inviting Me Once Again!
  • 3. A quick Kotlin refresher • Kotlin compared to Java • Functional coding in Kotlin • Reactive Programming in Kotlin Introducing Arrow • What is it and why does it matter? Arrow Pt1: Data Types • Option, Try, Either and Validated Arrow Pt2: Enhanced FP • Partial Invocation, Currying and Composition Arrow Pt3: Esoteric Stuff • Lenses, IO etc… Agenda For This Talk
  • 4. • In case this is all new to you… Kotlin Refresher
  • 6. Enter some numbers or three 'X' to finish 10 20 30 40 50 XXX Total of numbers is: 150 Enter some numbers or three 'X' to finish wibble Ignoring wibble 12 13 14 XXX Total of numbers is: 39 Enter some numbers or three 'X' to finish XXX Total of numbers is: 0
  • 7. public class Program { public static void main(String[] args) { @SuppressWarnings("resource") Scanner scanner = new Scanner(System.in); List<Integer> numbers = new ArrayList<>(); System.out.println("Enter some numbers or three 'X' to finish"); Pattern endOfInput = Pattern.compile("[X]{3}"); while(scanner.hasNextLine()) { if(scanner.hasNextInt()) { numbers.add(scanner.nextInt()); } else { if(scanner.hasNext(endOfInput)) { break; } else { String mysteryText = scanner.nextLine(); System.out.printf(“Ignoring %sn", mysteryText); } } } int total = numbers.stream().reduce((a,b) -> a + b).orElse(0); System.out.printf("Total of numbers is: %sn",total); } } A Sample Java Program
  • 8. fun main(args: Array<String>) { val numbers = mutableListOf<Int>() val scanner = Scanner(System.`in`) val endOfInput = Regex("[X]{3}") println("Enter some numbers or three 'X' to finish") while (scanner.hasNextLine()) { if (scanner.hasNextInt()) { numbers += scanner.nextInt() } else { if (scanner.hasNext(endOfInput.toPattern())) { break } else { val mysteryText = scanner.nextLine() println("Ignoring $mysteryText") } } } val total1 = numbers.fold(0,Int::plus) println("Total of numbers is: $total1") //simpler alternative in this case val total2 = numbers.sum() println("Total of numbers is: $total2") } The Sample Re-Written in Kotlin Points to note:  No redundant class  No semi-colons  Type inference  Both ‘val’ and ‘var’  Helper functions  String interpolation  Simplified collections  Interop with Java types  Simpler use of FP
  • 10. fun <T,U>map(input: List<T>, mappingFunc: (T)->U): List<U> { val results = ArrayList<U>() for (item in input) { results.add(mappingFunc(item)); } return results } fun <T>filter(input: List<T>, filterFunc: (T)->Boolean): List<T> { val results = ArrayList<T>() for (item in input) { if (filterFunc(item)) { results.add(item); } } return results } fun <T>partition(input: List<T>, filterFunc: (T)->Boolean): Pair<List<T>,List<T>> { val results = Pair(ArrayList<T>(),ArrayList<T>()) for (item in input) { if (filterFunc(item)) { results.first.add(item); } else { results.second.add(item); } } return results } Implementing Filter, Map and Partition
  • 11. fun main(args: Array<String>) { val originalData = arrayListOf<String>("12","34","56","78","90") val mappedData = map(originalData, String::toInt) val filteredData = filter(mappedData) { it > 50 } val partitionedData = partition(mappedData) { it > 50 } printResults("Results of mapping",mappedData) printResults("Results of filtering", filteredData) printResults("Results of partitioning", partitionedData) } fun<T> printResults(title: String, input: List<T>) { println("----- $title -----") for(item in input) { println("t$item") } } fun<T,U> printResults(title: String, input: Pair<List<T>,List<U>>) { println("----- $title -----") println("tfirst items in pair") for(item in input.first) { println("tt$item") } println("tsecond items in pair") for(item in input.second) { println("tt$item") } } Implementing Filter, Map and Partition
  • 12. Implementing Filter, Map and Partition ----- Results of mapping ----- 12 34 56 78 90 ----- Results of filtering ----- 56 78 90 ----- Results of partitioning ----- first items in pair 56 78 90 second items in pair 12 34
  • 13. fun wrapInH1(input: String) = "<h1>$input</h1>" fun wrapInH2(input: String) = "<h2>$input</h2>" fun wrapInTag(tagName: String, input: String): String { val openingTag = "<$tagName>" val closingTag = "</$tagName>" return "$openingTag$input$closingTag" } fun buildWrapper(tagName: String): (String) -> String { val openingTag = "<$tagName>" val closingTag = "</$tagName>" return { "$openingTag$it$closingTag" } } Using Functions as Outputs
  • 14. fun main(args: Array<String>) { println(wrapInH1("Marge")) println(wrapInH2("Homer")) println(wrapInTag("h3","Liza")) println(wrapInTag("h4","Bart")) val wrapInBold = buildWrapper("b") val wrapInItalics = buildWrapper("i") val wrapInMark = buildWrapper("mark") println(wrapInBold("Maggie")) println(wrapInItalics("Snowball III")) println(wrapInMark("Santas Little Helper")) } <h1>Marge</h1> <h2>Homer</h2> <h3>Liza</h3> <h4>Bart</h4> <b>Maggie</b> <i>Snowball III</i> <mark>Santas Little Helper</mark> Using Functions as Outputs
  • 16. fun main(args: Array<String>) { val loremIpsum = """Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.""" val flux = Flux.fromIterable(loremIpsum.split(" ")) flux.map { it.toLowerCase() } .flatMap { word -> Flux.fromArray(word.toCharArray() .toTypedArray()) } .filter { theChar -> Character.isLetter(theChar) } .collectMultimap { it } .map { table -> table.mapValues { entry -> entry.value.size } } .subscribe(::printTable) } Using Project Reactor To Process In-Memory Data
  • 17. fun printTable(input: Map<Char, Int>) { println("The frequency count of letters in 'lorem ipsum' is:") input.forEach { entry -> val msgWord = "instance" + if (entry.value > 1) "s" else "" println("${entry.value} $msgWord of ${entry.key}") } } The frequency count of letters in 'lorem ipsum' is: 29 instances of a 3 instances of b 16 instances of c 19 instances of d 38 instances of e 3 instances of f 3 instances of g 1 instance of h 42 instances of i 22 instances of l 17 instances of m 24 instances of n 29 instances of o 11 instances of p ... Using Reactor To Process In-Memory Data
  • 18. • What is it? • Why does it matter? Introducing Arrow
  • 19. Languages Today Are Converging
  • 20. The Great Scala vs. Kotlin Debate I am an Enterprise Coder. Like my father before me You fool. If only you knew the power of Monads!
  • 21. How Much Functional Programming is ‘Just Right’?
  • 23. Arrow is a functional programming library for Kotlin coders • Launched in Jan when the two leading libraries joined focus • To prevent the ‘Scalaz vs. Cats’ debate that exists in Scala It is not a formal part of the Kotlin environment • But is generating a lot of interest in the Kotlin community • It has resulted in proposals for changes to the language Learning Arrow can be a bit frustrating as: • The documentation is incomplete and patchy • Changes are still occurring between releases • Sample code is hard to find…. I’m still learning what its all about! • This is very much a report on my progress so far… Introducing Arrow
  • 24. Part One: Data Types
  • 25. Lets Do The Same Thing Many Times 
  • 27. fun readPropertyA(name: String): Option<String> { val result = System.getProperty(name) return if(result != null) Some(result) else None } fun readPropertyB(name: String) = Option.fromNullable(System.getProperty(name)) Reading Property Values Safely Via Option
  • 28. fun print1(input: Option<String>): Unit { when(input) { is None -> println("Nothing was found") is Some -> println("'${input.t}' was found") } } fun print2(input: Option<String>): Unit { println("${input.getOrElse { "Nothing" }} was found") } Reading Property Values Safely Via Option
  • 29. fun print3(input: Option<String>): Unit { val result = input.fold({ "Nothing" }, { it }) println("$result was found") } fun print4(input1: Option<String>, input2: Option<String>): Unit { val result = input1.flatMap { first -> input2.map { second -> "$first and $second" } } println("Results are ${result.getOrElse { "Nothing" }}") } Reading Property Values Safely Via Option
  • 30. fun main(args: Array<String>) { print1(readPropertyA("java.version")) print1(readPropertyA("wibble")) printLine() print2(readPropertyB("java.version")) print2(readPropertyB("wibble")) printLine() print3(readPropertyA("java.version")) print3(readPropertyA("wibble")) printLine() print4( readPropertyA("java.version"), readPropertyB("java.version") ) printLine() print4( readPropertyA("java.version"), readPropertyB("wibble") ) printLine() print4(readPropertyA("wibble"), readPropertyB("wibble")) printLine() print4(readPropertyA("wibble"), readPropertyB("wibble")) } Reading Property Values Safely Via Option
  • 31. Reading Property Values Safely Via Option '1.8.0_121' was found Nothing was found --------------- 1.8.0_121 was found Nothing was found --------------- 1.8.0_121 was found Nothing was found --------------- Results are 1.8.0_121 and 1.8.0_121 --------------- Results are Nothing --------------- Results are Nothing --------------- Results are Nothing
  • 32. class Postcode(val input: String?) { fun value() = Option.fromNullable(input) } class Address(val street: String, val postcode: Postcode?) { fun location() = Option.fromNullable(postcode) } class Person(val name: String, val address: Address?) { fun residence() = Option.fromNullable(address) } Using Option as a Monad
  • 33. fun printPostcode(person: Person) { val result = Option.monad().binding { val address = person.residence().bind() val location = address.location().bind() location.value().bind() }.fix() println(result.fold( { "No postcode available" }, { "Postcode of $it" })) } Using Option as a Monad
  • 34. fun main(args: Array<String>) { printPostcode(Person("Dave", Address("10 Arcatia Road", Postcode("ABC 123")))) printPostcode(Person("Dave", Address("10 Arcatia Road", null))) printPostcode(Person("Dave", null)) } Using Option as a Monad Postcode of ABC 123 No postcode available No postcode available
  • 35. Try
  • 36. fun firstLine(path: String): Try<String> { fun readFirstLine(path: String): String { val reader = BufferedReader(FileReader(path)) return reader.use { it.readLine() } } return Try { readFirstLine(path) } } Reading the First Line from a File via Try
  • 37. fun print1(input: Try<String>): Unit { when(input) { is Success -> println("Read '${input.value}'") is Failure -> println("Threw '${input.exception.message}'") } } fun print2(input: Try<String>): Unit { val result = input.fold( { "Threw '${it.message}'" }, { "Read '$it'" }) println(result) } fun print3(input: Try<String>): Unit { input.map { println("Read '$it'") } input.recover { println("Threw '${it.message}'") } } Reading the First Line from a File via Try
  • 38. Lets Have Some Fun 
  • 39. fun print4(input: String) { fun fullPath(str: String) = "data/$str" val finalResult = firstLine(fullPath(input)).flatMap { one -> firstLine(fullPath(one)).flatMap { two -> firstLine(fullPath(two)).flatMap { three -> firstLine(fullPath(three)).flatMap { four -> firstLine(fullPath(four)).map { result -> result } } } } } val message = finalResult.fold({ it.message }, { it }) println("Path navigation produced '$message'") } Reading the First Line from a File via Try
  • 40. fun main(args: Array<String>) { print1(firstLine("data/input4.txt")) print1(firstLine("foobar.txt")) printLine() print2(firstLine("data/input4.txt")) print2(firstLine("foobar.txt")) printLine() print3(firstLine("data/input4.txt")) print3(firstLine("foobar.txt")) printLine() print4("input.txt") print4("foobar.txt") } Reading the First Line from a File via Try
  • 41. Read 'Fortune favors the prepared mind' Threw 'foobar.txt (No such file or directory)' --------------- Read 'Fortune favors the prepared mind' Threw 'foobar.txt (No such file or directory)' --------------- Read 'Fortune favors the prepared mind' Threw 'foobar.txt (No such file or directory)' --------------- Path navigation produced 'Fortune favors the prepared mind' Path navigation produced 'data/foobar.txt (No such file or directory)'
  • 42. fun readFromFiles(input: String): String? { val result = Try.monad().binding { val one = firstLine(fullPath(input)).bind() val two = firstLine(fullPath(one)).bind() val three = firstLine(fullPath(two)).bind() val four = firstLine(fullPath(three)).bind() firstLine(fullPath(four)).bind() }.fix() return result.fold({ it.message }, { it }) } Reading the First Line from a File via Try
  • 43. fun main(args: Array<String>) { println("Path navigation produced '${readFromFiles("input.txt")}'") println("Path navigation produced '${readFromFiles("foobar")}'") } Path navigation produced 'Fortune favors the prepared mind' Path navigation produced 'data/foobar (No such file or directory)'
  • 45. fun genNumber() : Either<Int, Int> { val number = (random() * 100).toInt() return if(number % 2 == 0) Right(number) else Left(number) } fun main(args: Array<String>) { val results = (1 .. 10).map { genNumber().flatMap { first -> genNumber().map { second -> Pair(first, second) } } } results.forEach { result -> val msg = result.fold( { "Odd number $it" }, { "Even numbers ${it.first} and ${it.second}" } ) println(msg) } } Using the Either Type Even numbers 50 and 40 Odd number 77 Even numbers 52 and 32 Odd number 25 Odd number 89 Even numbers 80 and 54 Odd number 65 Odd number 1 Odd number 1 Odd number 33
  • 47. Our Sample Problem Whats your ID? ab12 How old are you? 19 Where do you work? HR Error: Bad ID Whats your ID? AB12 How old are you? 19 Where do you work? IT Result: AB12 of age 19 working in IT Whats your ID? ab12 How old are you? 14 Where do you work? Mars Error: Bad Dept Bad ID Bad Age
  • 48. class Employee(val id: String, val age: Int, val dept: String) { override fun toString() = "$id of age $age working in $dept" } fun askQuestion(question: String): String { println(question) return readLine() ?: "" } Reading and Validating Information
  • 49. fun checkID(): Validated<String, String> { val regex = Regex("[A-Z]{2}[0-9]{2}") val response = askQuestion("Whats your ID?") return if(regex.matches(response)) Valid(response) else Invalid("Bad ID") } fun checkAge(): Validated<String, Int> { val response = askQuestion("How old are you?").toInt() return if(response > 16) Valid(response) else Invalid("Bad Age") } fun checkDept(): Validated<String, String> { val depts = listOf("HR", "Sales", "IT") val response = askQuestion("Where do you work?") return if(depts.contains(response)) Valid(response) else Invalid("Bad Dept") } Reading and Validating Information
  • 50. fun main(args: Array<String>) { val sg = object : Semigroup<String> { override fun String.combine(b: String) = "$this $b" } val id = checkID() val age = checkAge() val dept = checkDept() val result = Validated.applicative(sg) .map(id, age, dept, { (a,b,c) -> Employee(a,b,c) }) .fix() println(result.fold({ "Error: $it" }, {"Result: $it"} )) } Reading and Validating Information
  • 52. Lets Play With Plugging Functions Together…
  • 54. fun demo1() { val addNums = { no1: Int, no2: Int -> println("Adding $no1 to $no2") no1 + no2 } val addSeven = addNums.partially2(7) val result = addSeven(3) println(result) } Partial Invocation Adding 3 to 7 10
  • 55. fun demo2() { val addNums = { no1: Int, no2: Int -> println("Adding $no1 to $no2") no1 + no2 } val addSeven = addNums.partially2(7) val addSevenToThree = addSeven.partially1(3) val result = addSevenToThree() println(result) } Partial Invocation Adding 3 to 7 10
  • 56. fun demo3() { val addNums = { no1: Int, no2: Int -> println("Adding $no1 to $no2") no1 + no2 } val addSeven = addNums.reverse().partially2(7) val result = addSeven(3) println(result) } Partial Invocation Adding 7 to 3 10
  • 57. fun grep(path: String, regex: Regex, action: (String) -> Unit) { val reader = BufferedReader(FileReader(path)) reader.use { it.lines() .filter { regex.matches(it) } .forEach(action) } } val grepLambda = { a: String, b: Regex, c: (String) -> Unit -> grep(a, b, c) } fun printLine() = println("-------------") Here’s Something More Useful
  • 58. val filePath = "data/grepInput.txt" val regex = "[A-Z]{2}[0-9]{2}".toRegex() grep(filePath, regex, ::println) printLine() grepLambda(filePath, regex, ::println) printLine() Here’s Something More Useful AB12 CD34 EF56 ------------- AB12 CD34 EF56 -------------
  • 59. val grepAndPrint = grepLambda.partially3(::println) grepAndPrint(filePath, regex) printLine() val sb = StringBuilder() val grepAndConcat = grepLambda.partially3 {sb.append(it)} grepAndConcat(filePath, regex) println(sb.toString()) printLine() val grepAndPrintRegex = grepAndPrint.partially2(regex) grepAndPrintRegex(filePath) Here’s Something More Useful AB12 CD34 EF56 ------------- AB12CD34EF56 ------------- AB12 CD34 EF56
  • 61. val addThree = { a:Int, b: Int, c:Int -> println("Adding $a, $b and $c") a + b + c } fun printLine() = println("--------------------") fun main(args: Array<String>) { println(addThree(10,20,40)) printLine() val f1 = addThree.curried() val f2 = f1(10) val f3 = f2(20) val result = f3(40) println(result) printLine() println(f1(10)(20)(40)) printLine() val f4 = addThree.reverse().curried() println(f4(10)(20)(40)) println() } The Basic Syntax of Currying Adding 10, 20 and 40 70 -------------------- Adding 10, 20 and 40 70 -------------------- Adding 10, 20 and 40 70 -------------------- Adding 40, 20 and 10 70
  • 62. fun grep(path: String, regex: Regex, action: (String) -> Unit) { val reader = BufferedReader(FileReader(path)) reader.use { it.lines() .filter { regex.matches(it) } .forEach(action) } } val grepLambda = { a: String, b: Regex, c: (String) -> Unit -> grep(a,b,c) } fun printLine() = println("-------------") A More Useful Example
  • 63. fun main(args: Array<String>) { val filePath = "data/grepInput.txt" val regex1 = "[A-Z]{2}[0-9]{2}".toRegex() val regex2 = "[a-z]{2}[0-9]{2}".toRegex() val f1 = grepLambda.curried() val grepInFile = f1(filePath) val grepRegex1 = grepInFile(regex1) val grepRegex2 = grepInFile(regex2) grepRegex1(::println) printLine() grepRegex2(::println) } A More Useful Example AB12 CD34 EF56 ------------- ab12 cd34 ef56
  • 65. val source = { name: String -> "data/$name" } val allLines = { path: String -> val reader = BufferedReader(FileReader(path)) reader.use { it.lines().toList() } } val findMatches = { input: List<String> -> val regex = "[A-Z]{2}[0-9]{2}".toRegex() input.filter(regex::matches) } Composing Functions Together
  • 66. fun main(args: Array<String>) { val composed1 = findMatches compose allLines compose source println(composed1("grepInput.txt")) val composed2 = source forwardCompose allLines forwardCompose findMatches println(composed2("grepInput.txt")) val composed3 = source andThen allLines andThen findMatches println(composed3("grepInput.txt")) } Composing Functions Together [AB12, CD34, EF56] [AB12, CD34, EF56] [AB12, CD34, EF56]
  • 67. Part 3: Weird Stuff
  • 69. @optics data class Postcode(val value: String) { override fun toString() = "$value" } @optics data class Address(val street: String, val postcode: Postcode) { override fun toString() = "$street ($postcode)" } @optics data class Person(val name: String, val address: Address) { override fun toString() = "$name living at $address" } Copying Immutable Structures With Lenses
  • 70. fun main(args: Array<String>) { val oldPerson = Person("Dave", Address("10 Arcatia Road", Postcode("BT26 ABC"))) println(oldPerson) val personAddressPostcode = personAddress() compose addressPostcode() compose postcodeValue() val newPerson = personAddressPostcode.modify(oldPerson, { _ -> "BT37 DEF" }) println(newPerson) } Copying Immutable Structures With Lenses Dave living at 10 Arcatia Road (BT26 ABC) Dave living at 10 Arcatia Road (BT37 DEF)