scala - 作家单子(monad)实际上与状态单子(monad)相同吗?

标签 scala monads scalaz state-monad writer-monad

有一个很棒的教程here这似乎向我表明 Writer Monad 基本上是一个特殊情况的元组对象,它代表 (A,B) 执行操作。 writer 在左侧累积值(即 A),并且 A 具有相应的 Monoid(因此它可以累积或改变状态)。如果 A 是一个集合,那么它会累积。

State Monad 也是一个处理内部元组的对象。它们都可以是 flatMap'd、map'd 等。操作对我来说似乎是一样的。它们有何不同? (请回复一个 scala 示例,我不熟悉 Haskel)。谢谢!

最佳答案

您认为这两个单子(monad)密切相关的直觉是完全正确的。区别在于 Writer受到更多限制,因为它不允许您读取累积状态(直到您最后兑现)。您唯一可以对 Writer 中的状态执行的操作是把更多的东西粘到最后。

更简洁地说,State[S, A]S => (S, A) 的一种包装器, 而 Writer[W, A](W, A) 的包装器.

考虑以下 Writer 的用法:

import scalaz._, Scalaz._

def addW(x: Int, y: Int): Writer[List[String], Int] =
  Writer(List(s"$x + $y"), x + y)

val w = for {
  a <- addW(1, 2)
  b <- addW(3, 4)
  c <- addW(a, b)
} yield c

现在我们可以运行计算:
scala> val (log, res) = w.run
log: List[String] = List(1 + 2, 3 + 4, 3 + 7)
res: Int = 10

我们可以用 State 做同样的事情。 :
def addS(x: Int, y: Int) =
  State((log: List[String]) => (log |+| List(s"$x + $y"), x + y))

val s = for {
  a <- addS(1, 2)
  b <- addS(3, 4)
  c <- addS(a, b)
} yield c

进而:
scala> val (log, res) = s.run(Nil)
log: List[String] = List(1 + 2, 3 + 4, 3 + 7)
res: Int = 10

但这有点冗长,我们还可以用 State 做很多其他事情我们无法使用 Writer .

所以这个故事的寓意是你应该使用Writer只要有可能,您的解决方案就会更干净、更简洁,并且您会因为使用了适当的抽象而感到满意。

经常Writer但是,不会为您提供所需的全部功能,在这些情况下 State会等你的。

关于scala - 作家单子(monad)实际上与状态单子(monad)相同吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23942890/

相关文章:

ios - 在其他 Monad 中提取 IO 数据

haskell - 列表的 writer monad 的效率如何?

list - 为什么我们有map、fmap和liftM?

scala - 如何理解traverse、traverseU和traverseM

scala - 如何使用 Scalaz 或 Cats 重构抛出异常的函数

scala - 如何使用隐式转换将List [A]转换为List [B]

scala - 从Scala解释器打印Unicode

scala - 在SBT中进行交叉构建时设置唯一的快照版本

Gradle 中的 Scala REPL

scala - Spark更改DF架构列从点重命名为下划线