【发布时间】:2021-12-11 06:00:21
【问题描述】:
我发现 monad 转换器的行为对我来说根本不直观。
以以下数据为例:
type F[X] = OptionT[Either[String, *], X]
val success: F[Int] = 1.pure[F]
val empty: F[Int] = ().raiseError[F, Int]
val failed = "Boom!".raiseError[Either[String, *], Int].liftTo[F]
然后执行一行:
(success, empty, failed).tupled.value // Right(None)
我们仍然得到Right,但我希望看到Left("Boom!"),因为Either 是最外层的效果。但是当订单稍作修改时:
(success, failed, empty).tupled.value // Left(Boom!)
这会产生一个预期值。另一件事是当我们在 tupled 之前从 monad 转换器中取出值并按初始顺序应用它们:
(success.value, empty.value, failed.value).tupled // Left(Boom!)
我们得到的值在我看来很直观,但与第一个示例的结果不一致。
有谁知道为什么 monad 转换器会以这种方式运行?我只是认为 monad 转换器是一种使用堆叠 monad 的便捷方式,但这似乎增加了更多深度,因为无论我是否使用它们,它实际上都可能产生不同的值。
【问题讨论】:
-
变形金刚用自己的行为形成了自己不同的
Monads,与展开的版本不同。OptionT的意义在于,如果其中的值是F[None],那么flatMap将返回另一个F[None],就像None上的flatMap返回None一样。
标签: scala functional-programming scala-cats monad-transformers