作家Monad是否与State Monad有效?

时间:2014-05-29 20:58:20

标签: scala monads scalaz state-monad writer-monad

有一个很棒的教程here似乎告诉我,Writer Monad基本上是一个特殊的案例元组对象,它代表(A,B)进行操作。作者在左边积累了值(即A),并且A与它有相应的Monoid(因此它可以累积或改变状态)。如果A是一个集合,那么它就会累积。

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

2 个答案:

答案 0 :(得分:35)

你对这两个单子密切相关的直觉是完全正确的。区别在于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会等着您。

答案 1 :(得分:1)

tl; dr状态是读写,而Writer是,只有写。

使用State,您可以访问存储的先前数据,并且可以在当前计算中使用此数据:

def myComputation(x: A) =
  State((myState: List[A]) => {
        val newValue = calculateNewValueBasedOnState(x,myState)
        (log |+| List(newValue), newValue)
  })

使用Writer,您可以将数据存储在您无法访问的某个对象中,您只能写入该对象。