Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save harikrishnan83/a16ef8f2e6f9287482adc2b29fbb23f2 to your computer and use it in GitHub Desktop.
Save harikrishnan83/a16ef8f2e6f9287482adc2b29fbb23f2 to your computer and use it in GitHub Desktop.
Kotlin Railway Oriented Programming with Arrow and Infix
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