Last active
June 14, 2020 06:46
-
-
Save harikrishnan83/a16ef8f2e6f9287482adc2b29fbb23f2 to your computer and use it in GitHub Desktop.
Kotlin Railway Oriented Programming with Arrow and Infix
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 arrow.core.Either | |
import arrow.core.flatMap | |
sealed class Result<T> | |
data class Success<T>(val message: T) : Result<T>() | |
data class Failure<T>(val errorMessage: T) : Result<T>() | |
infix fun <F, S> Either<F, S>.then(f: (S) -> Either<F, S>) = | |
this.flatMap { f(it) } | |
infix fun <F, S> Either<F, S>.handleError(f: (Result<HttpRequest>) -> Result<HttpRequest>) = | |
this.fold( | |
{ Failure(it) }, | |
{ Success(it) } | |
) | |
class HttpRequest(private val url: String, private val method: HttpMethod, private val body: String) { | |
fun matches(anotherRequest: HttpRequest) = | |
matchAnotherRequest(anotherRequest) | |
private fun matchAnotherRequest(anotherRequest: HttpRequest) = | |
Either.Right(anotherRequest) then | |
::matchUrl then | |
::matchMethod then | |
::matchBody handleError | |
::result | |
/* | |
//Without Infix, the flatMap can get in the way of readability. Otherwise this is equivalent to the | |
//above implementation of matchAnotherRequest. | |
private fun matchAnotherRequest(anotherRequest: HttpRequest) = | |
matchUrl(anotherRequest) .flatMap { | |
matchMethod(it) }.flatMap { | |
matchBody(it) }.fold({ Failure(it) }, { Success(it) }) | |
*/ | |
private fun matchUrl(anotherRequest: HttpRequest): Either<String, HttpRequest> { | |
if (this.url != anotherRequest.url) | |
return Either.Left("URL did not match. ${this.url} not equal to ${anotherRequest.url}") | |
return Either.Right(anotherRequest) | |
} | |
private fun matchMethod(anotherRequest: HttpRequest): Either<String, HttpRequest> { | |
if (this.method != anotherRequest.method) | |
return Either.Left("Method did not match. ${this.method} not equal to ${anotherRequest.method}") | |
return Either.Right(anotherRequest) | |
} | |
private fun matchBody(anotherRequest: HttpRequest): Either<String, HttpRequest> { | |
if (this.body != anotherRequest.body) | |
return Either.Left("Body did not match. ${this.method} not equal to ${anotherRequest.method}") | |
return Either.Right(anotherRequest) | |
} | |
private fun result(result: Result<HttpRequest>) = result | |
} | |
sealed class HttpMethod { | |
object GET : HttpMethod() { | |
override fun toString(): String { | |
return "GET" | |
} | |
} | |
object POST : HttpMethod() { | |
override fun toString(): String { | |
return "POST" | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment