您认为这两个 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 会等着您。