我已经定义了Result
这样的类型:
sealed class BadResult {
data class Description(val description: String): BadResult()
data class Exception (val exception : Throwable): BadResult()
}
sealed class BadTree {
data class Leaf(val v: BadResult) : BadTree()
data class Fork(val l: BadTree, val r: BadTree) : BadTree()
}
sealed class Result<T> {
data class Good<T> (val good : T ) : Result<T>()
class Empty<T> : Result<T>()
data class Bad <T> (val badTree : BadTree ) : Result<T>()
}
fun <T> T.good() : Result<T> = Result.Good(this)
fun <T> empty() : Result<T> = Result.Empty()
fun <T> BadTree.bad() : Result<T> = Result.Bad<T>(this)
fun <T> String.bad() : Result<T> = BadTree.Leaf(BadResult.Description(this)).bad()
fun <T> Throwable.bad() : Result<T> = BadTree.Leaf(BadResult.Exception(this)).bad()
对于这个Result
课程,我定义了monadic bind
:
infix fun <T, U> Result<T>.bind(uf: (T) -> Result<U>) : Result<U> {
return when(this) {
is Result.Good -> uf(this.good)
is Result.Empty -> empty()
is Result.Bad -> this.badTree.bad()
}
}
一个非常有用的函数模式是Applicative
,如果应用于Result
,这将允许我调用带有arbritrary参数列表的函数,当且仅当所有参数都是Good
时。
这是一种通常依赖于部分应用(又称currying)的技术,其中AFAIK在kotlin中不支持开箱即用。我已经看到一些图书馆尝试做曲,但在我看来,curry并不是kotlin中普遍认可的习语。
我理想的写作是这样的:
pure(::aFunctionThatTakes3Args) apply arg1 apply arg2 apply arg3
但我无法想出签名的样子。
我可以为函数的每个arity创建一个lift
函数,但很快就会变得很麻烦。
lift(::aFunctionThatTakes3Args, arg1, arg2, arg3) // lift is overloaded for each arity
(这似乎是funKTionale实现currying的方式)
欢迎任何想法。