Ulr*_*ter 4 monads kotlin reader-monad arrow-kt
我正在开发一个中型 Kotlin 项目,我需要通过纯函数的许多嵌套调用来线程化从文件读取的配置信息。对于 Reader monad 来说,这似乎是一个明显的例子。但是,我还没有弄清楚如何在 Kotlin 中有效地实现 Reader。
我正在使用 Arrow 库 (v1.1.3),但令我惊讶的是,它没有附带 Reader 的实现。使用 Arrow 通过函数调用来线程化配置数据的首选方法是什么?由于 Arrow 已转向使用 Kotlin 的本机挂起系统来理解 monad,我认为这意味着不需要专门的 Reader 实现。该怎么做呢?
Arrow 过去曾经有 reader monad,但从那时起我们就不再支持此类包装器,转而支持 Kotlin 惯用模式。
在 Kotlin 中,有多种方法可以解决这个问题,但最有希望的是context receivers.
然而,这在 Kotlin 中还不稳定,目前仅适用于 JVM。有一种方法可以使用扩展函数来解决相同的问题,但目前需要更多的样板文件。R您可以扩展( )的泛型类型Reader,并限制R您需要的实例。
suspend fun <R> R.getProcessUsers(/* add any arguments as needed */): Either<ProcessingError, List<ProcessedUser>>
where R : Repo,
R : Persistence =
fetchUsers().process()
Run Code Online (Sandbox Code Playgroud)
为了最终调用这个函数,您需要R具体化,您可以通过创建RepoandPersistence和接口来实现这一点,然后您可以使用委托。
class DataModule(
persistence: Persistence,
repo: Repo
) : Persistence by persistence, Repo by repo
suspend fun main(): Unit {
// This is your router { get { } } router definition or
// your Android launch { } or compose function.
// Generic top-level function automatically got enabled
val processedUsers = DataModule(MockPersistence(), MockRepo()).getProcessUsers()
println(processedUsers)
// Call the alternative approach
val processedUsers2 = DataModule2(MockPersistence(), MockRepo()).getProcessUsers2()
println(processedUsers2)
}
Run Code Online (Sandbox Code Playgroud)
然而仍然可以实现Reader,但它可能应该是ReaderT实现suspend它的一个版本的变体。
编辑:
suspend类似于 Arrow 的 DSL支持的实现Reader可以这样实现:
public class Reader<R, A>(public val reader: suspend (R) -> A) {
public companion object {
public fun <R> ask(): Reader<R, R> = Reader { it }
}
public fun <T> local(f: (T) -> R): Reader<T, A> = Reader { r: T -> reader(f(r)) }
}
public interface ReaderEffect<R> {
public suspend fun <A> Reader<R, A>.bind(): A
}
public fun <R, A> reader(action: suspend ReaderEffect<R>.(R) -> A): Reader<R, A> =
Reader { r ->
val effect = object : ReaderEffect<R> {
override suspend fun <A> Reader<R, A>.bind(): A = reader(r)
}
action(effect, r)
}
public val one: Reader<String, Int> = reader { input -> input.toInt() }
public val sum: Reader<String, Int> = reader { one.bind() + one.bind() }
public suspend fun main(): Unit {
val res = sum.reader.invoke("1")
println(res) // 2
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
663 次 |
| 最近记录: |