Является ли писательская монада такой же, как государственная монада?
Здесь есть большое руководство, которое, кажется, подсказывает мне, что Монада Writer - это в основном объект кортежа особого случая, который выполняет операции от имени (A,B). Автор накапливает значения слева (то есть A), и что A имеет соответствующий моноид с ним (следовательно, он может накапливать или изменять состояние). Если A является коллекцией, то она накапливается.
Государственная монада также является объектом, который имеет дело с внутренним кортежем. Они оба могут быть flatMap'd, map'd и т. Д. И операции кажутся мне одинаковыми. Насколько они разные? (пожалуйста, ответьте примером с scala, я не знаком с Хаскелем). Спасибо!
2 ответа
Ваша интуиция о том, что эти две монады тесно связаны, абсолютно верна. Разница в том, что 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
буду ждать тебя.
tl;dr State - это чтение и запись, в то время как Writer - это только запись.
С State у вас есть доступ к предыдущим сохраненным данным, и вы можете использовать эти данные в ваших текущих вычислениях:
def myComputation(x: A) =
State((myState: List[A]) => {
val newValue = calculateNewValueBasedOnState(x,myState)
(log |+| List(newValue), newValue)
})
С Writer вы можете хранить данные в каком-то объекте, к которому у вас нет доступа, вы можете записывать только в этот объект.