|
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) |
|
|
|
// 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!") |
|
|
|
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!" }) |
|
} |