如何在生产者频道的 Kotlin/Arrow.kt 中实施 "Railway Pattern"
How to Implement "Railway Pattern" in Kotlin/Arrow.kt for producer Channel
我正在研究当前 Android 应用程序中的 Kotlin 协程和通道。
我有以下代码管理远程 Api 调用和控制 UI 副作用
private val historical: CompletableDeferred<List<Any>> = CompletableDeferred()
private val mutex = Mutex()
@ExperimentalCoroutinesApi
fun perform(action: Action): ReceiveChannel<List<Any>> =
produce {
mutex.withLock {
if (historical.isCompleted) {
send(historical.getCompleted())
return@produce
}
send(action.sideEffects)
val networkResponse = repository.perform(action)
send(networkResponse.sideEffects)
send(listOf(networkResponse)).also {
historical.complete(listOf(response))
}
}
}
上面的代码给了我想要的结果,但是我想将它重构为类似的东西
函数式编程 "Railway Pattern" https://android.jlelse.eu/real-world-functional-programming-with-kotlin-arrow-b5a98e72f5e3
我的流程在哪里
stepOne(Historical.completed)
.stepTwo(action.sideEffects)
.stepThree(getReaction())
.stepFour(reaction.sideEffects)
.finalStep(reaction)
这将 "short circuit" 在任何步骤失败时或历史 "isCompleted"
在Kotlin中是否可以实现这种调用方式? and/or 科特林 & Arrow.kt?
您可以使用 Arrow-kt 的 Either。
您可以使用 Either's
mapLeft()
, map()
, flatMap()
.
如果结果是 Exception
使用 mapLeft()
。 mapLeft()
的返回值在结果 Either
中将是新的 Left
,例如 return 是 String
,结果将是 Either<String, List<Any>>
。如果结果是 Right
,即 List<Any>
,mapLeft()
将被跳过,但结果类型无论如何都会改变,因此您将具有 Either<String, List<Any>>
的类型和 [=26] 的值=].您也可以 return 来自 mapLeft()
的 Exception
如果您选择
如果你不需要处理特定的错误,你可以只链接 map()
和 flatMap()
。 map()
基本上是 mapRight() 并且 flatMap()
在您想要链式调用时很有用,即链中某处有一个 List<Any>
的接收器,它可能会失败并且您想处理 Exception
与 Either
相同的调用方式,你可以 return new Either
from flatMap()
代码看起来像这样
fun perform(action: Either<Exception, Action>): ReceiveChannel<List<Any>> =
produce {
// if action is always right, you can start it as Right(action) but then first mapLeft does not make any sense
if (historical.completed) action
.mapLeft {
// handle actions exception here
// transform it to something else or just return it
send(action.sideEffects)
it
}.flatMap {
// handle right side of action either
// assume here that repository may fail and returns Either<Exception, NetworkResponse>
repository.perform(it)
}.mapLeft {
// handle repositorys exception here
// transform it to something else or just return it
send(it)
it
}.map {
// handle network response
send(listOf(networkResponse))
historical.complete(listOf(networkResponse))
}
}
我正在研究当前 Android 应用程序中的 Kotlin 协程和通道。
我有以下代码管理远程 Api 调用和控制 UI 副作用
private val historical: CompletableDeferred<List<Any>> = CompletableDeferred()
private val mutex = Mutex()
@ExperimentalCoroutinesApi
fun perform(action: Action): ReceiveChannel<List<Any>> =
produce {
mutex.withLock {
if (historical.isCompleted) {
send(historical.getCompleted())
return@produce
}
send(action.sideEffects)
val networkResponse = repository.perform(action)
send(networkResponse.sideEffects)
send(listOf(networkResponse)).also {
historical.complete(listOf(response))
}
}
}
上面的代码给了我想要的结果,但是我想将它重构为类似的东西 函数式编程 "Railway Pattern" https://android.jlelse.eu/real-world-functional-programming-with-kotlin-arrow-b5a98e72f5e3
我的流程在哪里
stepOne(Historical.completed)
.stepTwo(action.sideEffects)
.stepThree(getReaction())
.stepFour(reaction.sideEffects)
.finalStep(reaction)
这将 "short circuit" 在任何步骤失败时或历史 "isCompleted"
在Kotlin中是否可以实现这种调用方式? and/or 科特林 & Arrow.kt?
您可以使用 Arrow-kt 的 Either。
您可以使用 Either's
mapLeft()
, map()
, flatMap()
.
如果结果是 Exception
使用 mapLeft()
。 mapLeft()
的返回值在结果 Either
中将是新的 Left
,例如 return 是 String
,结果将是 Either<String, List<Any>>
。如果结果是 Right
,即 List<Any>
,mapLeft()
将被跳过,但结果类型无论如何都会改变,因此您将具有 Either<String, List<Any>>
的类型和 [=26] 的值=].您也可以 return 来自 mapLeft()
的 Exception
如果您选择
如果你不需要处理特定的错误,你可以只链接 map()
和 flatMap()
。 map()
基本上是 mapRight() 并且 flatMap()
在您想要链式调用时很有用,即链中某处有一个 List<Any>
的接收器,它可能会失败并且您想处理 Exception
与 Either
相同的调用方式,你可以 return new Either
from flatMap()
代码看起来像这样
fun perform(action: Either<Exception, Action>): ReceiveChannel<List<Any>> =
produce {
// if action is always right, you can start it as Right(action) but then first mapLeft does not make any sense
if (historical.completed) action
.mapLeft {
// handle actions exception here
// transform it to something else or just return it
send(action.sideEffects)
it
}.flatMap {
// handle right side of action either
// assume here that repository may fail and returns Either<Exception, NetworkResponse>
repository.perform(it)
}.mapLeft {
// handle repositorys exception here
// transform it to something else or just return it
send(it)
it
}.map {
// handle network response
send(listOf(networkResponse))
historical.complete(listOf(networkResponse))
}
}