Ответ 1
Ваша интуиция в том, что эти две монады тесно связаны, точно верна. Разница в том, что 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
будет ждать вас.