SlideShare a Scribd company logo
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)

More Related Content

PPTX
Coding in Kotlin with Arrow NIDC 2018
PPTX
Introduction to the basics of Python programming (part 1)
PPTX
Introduction to the basics of Python programming (part 3)
PPTX
Python in 30 minutes!
PPTX
Introduction to Haskell: 2011-04-13
PDF
Kotlin Slides from Devoxx 2011
PPTX
Python 3.6 Features 20161207
PPT
Profiling and optimization
Coding in Kotlin with Arrow NIDC 2018
Introduction to the basics of Python programming (part 1)
Introduction to the basics of Python programming (part 3)
Python in 30 minutes!
Introduction to Haskell: 2011-04-13
Kotlin Slides from Devoxx 2011
Python 3.6 Features 20161207
Profiling and optimization

What's hot (20)

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

Similar to The Arrow Library in Kotlin (20)

PPT
The Kotlin Programming Language
ODP
Functions In Scala
PDF
Kotlin @ Devoxx 2011
PPTX
Mixing functional programming approaches in an object oriented language
PPTX
Arrow 101 - Kotlin funcional com Arrow
ODP
Scala introduction
PDF
Cocoaheads Meetup / Alex Zimin / Swift magic
PDF
АлДĐșŃĐ°ĐœĐŽŃ€ Đ—ĐžĐŒĐžĐœ (Alexander Zimin) — Магоя Swift
PPT
Arrays
PDF
Functional programming in C++
PDF
Functional Programming You Already Know - Kevlin Henney - Codemotion Rome 2015
PPTX
TDC2016POA | Trilha .NET - C# como vocĂȘ nunca viu: conceitos avançados de pro...
PDF
Functional programming ii
PDF
Create a menu-driven program that will accept a collection of non-ne.pdf
PDF
Advanced Web Technology ass.pdf
PPTX
Functional Programming in Swift
PPTX
funadamentals of python programming language (right from scratch)
PDF
Rethink programming: a functional approach
PPTX
Keep it Stupidly Simple Introduce Python
PDF
Taming Asynchronous Transforms with Interstellar
The Kotlin Programming Language
Functions In Scala
Kotlin @ Devoxx 2011
Mixing functional programming approaches in an object oriented language
Arrow 101 - Kotlin funcional com Arrow
Scala introduction
Cocoaheads Meetup / Alex Zimin / Swift magic
АлДĐșŃĐ°ĐœĐŽŃ€ Đ—ĐžĐŒĐžĐœ (Alexander Zimin) — Магоя Swift
Arrays
Functional programming in C++
Functional Programming You Already Know - Kevlin Henney - Codemotion Rome 2015
TDC2016POA | Trilha .NET - C# como vocĂȘ nunca viu: conceitos avançados de pro...
Functional programming ii
Create a menu-driven program that will accept a collection of non-ne.pdf
Advanced Web Technology ass.pdf
Functional Programming in Swift
funadamentals of python programming language (right from scratch)
Rethink programming: a functional approach
Keep it Stupidly Simple Introduce Python
Taming Asynchronous Transforms with Interstellar

More from Garth Gilmour (20)

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

Recently uploaded (20)

PPTX
Odoo POS Development Services by CandidRoot Solutions
PDF
Adobe Illustrator 28.6 Crack My Vision of Vector Design
PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PDF
PTS Company Brochure 2025 (1).pdf.......
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PDF
top salesforce developer skills in 2025.pdf
PDF
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
PDF
Digital Strategies for Manufacturing Companies
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PPTX
history of c programming in notes for students .pptx
PDF
AI in Product Development-omnex systems
PDF
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PDF
medical staffing services at VALiNTRY
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PPTX
Introduction to Artificial Intelligence
PDF
Design an Analysis of Algorithms I-SECS-1021-03
PPTX
Reimagine Home Health with the Power of Agentic AI​
PPTX
ai tools demonstartion for schools and inter college
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
Odoo POS Development Services by CandidRoot Solutions
Adobe Illustrator 28.6 Crack My Vision of Vector Design
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PTS Company Brochure 2025 (1).pdf.......
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
top salesforce developer skills in 2025.pdf
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
Digital Strategies for Manufacturing Companies
VVF-Customer-Presentation2025-Ver1.9.pptx
history of c programming in notes for students .pptx
AI in Product Development-omnex systems
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
Wondershare Filmora 15 Crack With Activation Key [2025
medical staffing services at VALiNTRY
How to Choose the Right IT Partner for Your Business in Malaysia
Introduction to Artificial Intelligence
Design an Analysis of Algorithms I-SECS-1021-03
Reimagine Home Health with the Power of Agentic AI​
ai tools demonstartion for schools and inter college
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool

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)