Created
May 22, 2019 14:46
-
-
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
This file contains 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 characters
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) |
This file contains 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 characters
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