Arrow of outrageous fortune
Functional Programming in Kotlin
David Rawson
class Author(val firstName: String,
val lastName: String) extends Comparable[Author] {
override def compareTo(that: Author) = {
val lastNameComp = this.lastName compareTo that.lastName
if (lastNameComp != 0) lastNameComp
else this.firstName compareTo that.firstName
}
}
object Author {
def loadAuthorsFromFile(file: java.io.File): List[Author] = ???
}
class Author(val firstName: String,
val lastName: String) extends Comparable[Author] {
override def compareTo(that: Author) = {
val lastNameComp = this.lastName compareTo that.lastName
if (lastNameComp != 0) lastNameComp
else this.firstName compareTo that.firstName
}
}
object Author {
def loadAuthorsFromFile(file: java.io.File): List[Author] = ???
}
import java.io.File
class Author(
val firstName: String,
val lastName: String
) : Comparable<Author> {
override fun compareTo(that: Author) {
val lastNameComp = this.lastName.compareTo(that.lastName)
return if (lastNameComp != 0) {
lastNameComp
} else {
this.firstName.compareTo(that.firstName)
}
}
}
object Authors {
fun loadAuthorsFromFile(file: File): List<Author> = TODO()
}
import java.io.File
class Author(
val firstName: String,
val lastName: String
) : Comparable<Author> {
override fun compareTo(that: Author) = compareValuesBy(
this,
that,
Author::lastName,
Author::firstName
)
}
object Authors {
fun loadAuthorsFromFile(file: File): List<Author> = TODO()
}
plugins {
java
kotlin("jvm") version "1.4.10"
}
group = "org.example"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
implementation(kotlin("stdlib"))
testCompile("junit", "junit", "4.12")
}
fun main() {
val immutable = listOf(1, 2, 3)
val mutable = mutableListOf(1, 2, 3)
val david = Person(Name("David"), Age(21))
val olderDavid = david.copy(age = Age(22))
}
https://arrow-kt.io/
Our initial positive impressions of Arrow were confirmed when using it to build applications that are now in production.
core
fx
optics
meta
Typeclass-o-pedia
Typeclass-o-pedia
Typeclass-o-pedia
Typeclass-o-pedia
Typeclass-o-pedia
Typeclass-o-pedia
Error handling
data class Name(val name: String)
data class Age(val age: Int)
data class Person(val name: Name, val age: Age)
object TestClassic {
fun makeName(name: String?): Name {
if (name == null || name == "") {
throw IllegalArgumentException("Name cannot be null or empty")
}
return Name(name)
}
fun makeAge(age: String): Age {
val parsedAge = age.toInt()
require(0 <= parsedAge) {
"Ages must be non-negative"
}
return Age(parsedAge)
}
}
fun main(args: Array<String>) {
try {
val name = TestClassic.makeName(args[0])
val age = TestClassic.makeAge(args[1])
val person = Person(name, age)
println(person)
} catch (e: Exception) {
println("Could not make a person!")
}
}
import arrow.core.Either
object TestEither {
fun makeName(name: String?): Either<Throwable, Name> {
return when (name) {
null, "" -> return Either.Left(IllegalArgumentException())
else -> Either.Right(Name(name))
}
}
fun makeAge(age: String): Either<Throwable, Age> =
Either.catch {
age.toInt()
}.flatMap {
when {
it <= 0 -> Either.Left(IllegalArgumentException())
else -> Either.Right(it)
}
}.map {
Age(it)
}
}
import arrow.core.Either
fun main(args: Array<String>) {
TestEither.makeName(args[0]).flatMap { name ->
TestEither.makeAge(args[1]).map { age ->
Person(name, age)
}
}.fold(
ifLeft = {
"Could not make a person!"
},
ifRight = {
it.toString()
}
).let {
println(it)
}
}
import arrow.core.computations.either
suspend fun main(args: Array<String>) {
either<Throwable, Person> {
val name = TestEither.makeName(args[0]).bind()
val age = TestEither.makeAge(args[1]).bind()
Person(name, age)
}.fold(
ifLeft = {
"Could not make a person!"
} ,
ifRight = {
it
}
).let {
println(it)
}
}
https://medium.com/@heyitsmohit/writing-kotlin-compiler-plugin-with-arrow-meta-cf7b3689aa3e
https://medium.com/@heyitsmohit/writing-kotlin-compiler-plugin-with-arrow-meta-cf7b3689aa3e
intercepts
data class Age(val age: Int)
object TestClassic {
fun makeAge(age: String): Age {
val parsedAge = age.toInt()
require(0 < parsedAge) {
"Ages must be positive"
}
return Age(parsedAge)
}
}
data class PositiveInt(val value: Int) {
init {
require(0 < value) {
"Should be positive"
}
}
}
@Refinement
inline class PositiveInt(val value: Int) {
companion object : Refined<Int, PositiveInt> {
override val target : (Int) -> PositiveInt = ::PositiveInt
override val validate: Int.() -> Map<String, Boolean> = {
mapOf(
"Should be > 0" to (this > 0)
)
}
}
}
@Coercion
fun Int.positive(): PositiveInt? =
PositiveInt.from(this)