Last active
February 18, 2022 14:17
-
-
Save marc0der/6012b751849661fd71927887ec6b1570 to your computer and use it in GitHub Desktop.
Revisions
-
marc0der revised this gist
Dec 22, 2021 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -27,13 +27,13 @@ fun <A, B> Option<A>.flatMap(f: (A) -> Option<B>): Option<B> = fun <A> Option.Companion.unit(a: A): Option<A> = Some(a) // extra fun <A> Option<A>.getOrElse(f: () -> A): A = when(this) { is Some -> this.get is None -> f() } */ fun <A> remote(f: () -> A): A = if (Math.random() > 0.2) f() else throw IOException("boom!") -
marc0der created this gist
Dec 22, 2021 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,48 @@ # Functional error handling in Kotlin ## Agenda: * About the (simple) exercise * Higher Order Functions * Throwing exceptions: here be dragons!! * Sentinel values: better but not great * The `Option`: error as an ADT * Functional combinators: add some sugar * Trapping exceptions * Defer exception handling * Monad comprehensions with Arrow.kt ## Functional concepts in this session: * HOFs (Higher Order Functions) * Monad * Functor * Comprehension ## The problem domain Provide a function that performs a simple arithmetic calculation: ```kotlin fun calculate(a: Int, b: Int): Result<Int, Int> ``` 1. Multiply the two numbers (product) 2. Add the two numbers (sum) 3. Divide the product (dividend) by the sum (divisor) 4. Calculate the quotient and remainder as `Result<Int, Int>` **All calculation steps to be performed over a dodgy network!!!** ### Example ``` a = 11 b = 5 product = 55 sum = 16 quotient = 3 remainder = 7 ``` This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,81 @@ package fpinkotlin import arrow.core.None import arrow.core.Option import arrow.core.Some import arrow.core.computations.option import arrow.core.getOrElse import java.io.IOException /* sealed class Option<out A> { companion object } data class Some<out A>(val get: A): Option<A>() object None : Option<Nothing>() // functor fun <A, B> Option<A>.map(f: (A) -> B): Option<B> = when(this) { is Some -> Option.unit(f(this.get)) is None -> None } // monad fun <A, B> Option<A>.flatMap(f: (A) -> Option<B>): Option<B> = this.map { a -> f(a) }.getOrElse { None } fun <A> Option.Companion.unit(a: A): Option<A> = Some(a) fun <A> Option<A>.getOrElse(f: () -> A): A = when(this) { is Some -> this.get is None -> f() } */ fun <A> remote(f: () -> A): A = if (Math.random() > 0.2) f() else throw IOException("boom!") fun <A> trap(f: () -> A): Option<A> = try { Some(f()) } catch (e: Throwable) { None } typealias Result = Pair<Int, Int> fun calculate1(a: Int, b: Int): Option<Result> = multiply(a, b).flatMap { product -> add(a, b).flatMap { sum -> divide(product, sum).flatMap { quotient -> modulo(product, sum).map { rem -> quotient to rem } } } } suspend fun calculate2(a: Int, b: Int): Option<Result> = option { val product = multiply(a, b).bind() val sum = add(a, b).bind() val quotient = divide(product, sum).bind() val rem = modulo(product, sum).bind() quotient to rem } private fun multiply(a: Int, b: Int) = trap { remote { a * b } } private fun add(a: Int, b: Int) = trap { remote { a + b } } private fun divide(product: Int, sum: Int) = trap { remote { product / sum } } private fun modulo(product: Int, sum: Int) = trap { remote { product % sum } } suspend fun main() { println(calculate1(11, 5).getOrElse { "computer says no!" }) println(calculate2(11, 5).getOrElse { "computer says no!" }) }