我是 Arrow 的新手,并试图建立我的心智模型来了解它的效果系统是如何工作的;特别是它如何利用 Kotlin 的suspend
系统。我非常模糊的理解如下;如果有人可以确认,澄清或更正它,那就太好了:
因为 Kotlin 不支持更高级的类型,所以将 applicatives 和 monads 实现为类型类是很麻烦的。相反,arrow 从 Kotlin 的挂起机制提供的延续原语中为 Arrow 的所有单子类型派生其单子功能(绑定和返回)。这是正确的吗?特别是,短路行为(例如,fornullable
或either
)以某种方式实现为定界延续。我不太明白 Kotlin 的暂停机制的哪个特定功能在这里发挥了作用。
如果以上大致正确,我有两个后续问题:我应该如何包含非 IO 单子操作的范围?举一个简单的对象构造和验证示例:
suspend fun mkMessage(msgType: String, appRef: String, pId: String): Message? = nullable {
val type = MessageType.mkMessageType(msgType).bind()
val ref = ApplRefe.mkAppRef((appRef)).bind()
val id = Id.mkId(pId).bind()
Message(type, ref, id)
}
在 Haskell 的 do-notation 中,这将是
mkMessage :: String -> String -> String -> Maybe Message
mkMessage msgType appRef pId = do
type <- mkMessageType msgType
ref <- mkAppRef appRef
id <- mkId pId
return (Message type ref id)
在这两种情况下,该函数都返回 monad 类型(一个可为空的值,分别是 Maybe)。然而,虽然我可以在任何我认为合适的地方使用 Haskell 中的纯函数,但 Kotlin 中的挂起函数只能从挂起函数中调用。这样,Arrow 中一个简单的、非 IO monad 理解的行为就像一个 IO monad,必须在我的代码库中进行线程化;我想这是因为挂起机制是为实际的 IO 操作设计的。在 Arrow 中实现非 IO monad 理解而不使所有函数都变成挂起函数的推荐方法是什么?或者这实际上是要走的路?
第二:如果除了非 IO 单子(可为空、读取器等)之外,我还想要 IO - 例如,读取文件并解析它 - 我将如何结合这两种效果?说会有多个挂起范围对应于所涉及的不同 monad 是否正确,并且我需要以某种方式嵌套这些范围,就像我在 Haskell 中堆叠 monad 转换器一样?
上面的两个问题可能意味着我仍然缺乏在 Kotlin 的挂起机制上基于 continuation 的实现与 Haskell 中的通用 monad-as-typeclass 实现之间架起桥梁的心智模型。