Skip to content

Instantly share code, notes, and snippets.

@ch4vi
Created May 22, 2019 14:46
Show Gist options
  • Save ch4vi/eeff387ba421ded97ae45c267a7a779b to your computer and use it in GitHub Desktop.
Save ch4vi/eeff387ba421ded97ae45c267a7a779b to your computer and use it in GitHub Desktop.
My approximation to Railway oriented programing based on https://gist.github.com/antonyharfield/1928d02a1163cf115d701deca5b99f63
sealed class Result<T> {
data class Success<T>(val value: T) : Result<T>()
data class Failure<T>(val message: String? = null) : Result<T>()
val isSuccess get() = this is Success
val isFailure get() = this is Failure
fun <T> success(v: T) = Success(v)
fun <T> failure(m: String? = null) = Failure<T>(m)
fun <R> fold(failure: (String?) -> R, success: (T) -> R): R =
when (this) {
is Success -> success(value)
is Failure -> failure(message)
}
inline fun <R> map(crossinline f: (T) -> R): Result<R> =
fold({ Failure(it) }, { Success(f(it)) })
inline fun <S> flatMap(crossinline f: (T) -> Result<S>): Result<S> =
fold({ Failure(it) }, { f(it) })
fun getSuccess(): T? = when (this) {
is Success -> value
is Failure -> null
}
fun getFailure(): String? = when (this) {
is Success -> null
is Failure -> message
}
}
// Composition: apply a function f to Success results
inline infix fun <T, U> Result<T>.then(crossinline f: (T) -> Result<U>): Result<U> {
// println(this)
return fold({ Result.Failure(it) }, { f(it) })
}
// Pipe input: the beginning of a railway
infix fun <T, U> T.to(f: (T) -> Result<U>) = Result.Success(this) then f
// Handle error output: the end of a railway
infix fun <T> Result<T>.otherwise(f: (String?) -> Unit) =
if (this is Result.Failure) f(this.message) else Unit
fun <S> Success(success: S): Result<S> = Result.Success(success)
fun <F> Failure(failure: String?): Result<F> = Result.Failure(failure)
import org.junit.Test
class ResultUnitTest {
val qux = "qux"
@Test
fun resultInfixTest() {
println("infix")
qux to ::foobar then ::bar then ::quux then ::quux otherwise ::onError
// equivalent
println("not infix")
foobar(qux).flatMap { bar(it) }.flatMap { quux(it) }.flatMap { quux(it) }.fold(::onError) {
println("OK")
}
println()
}
fun foobar(v: String): Result<AnObject> {
print("foobar ->")
// return Failure("buuuu")
return Success(AnObject(v))
}
fun bar(v: AnObject): Result<OtherObject> {
print("bar ->")
// return Success(OtherObject(v))
return Failure("buuuu")
}
fun quux(v: OtherObject): Result<OtherObject> {
print("quux ->")
return Success(OtherObject(v.param))
}
fun onError(m: String?) {
print("onError $m ->")
}
}
class AnObject(val param: String)
class OtherObject(val param: String)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment