【发布时间】:2017-05-30 06:21:30
【问题描述】:
在阅读了Functional Programming in Scala 的第六章并试图理解 State monad 之后,我有一个关于包装副作用类的问题。
假设我有一个以某种方式修改自身的类。
class SideEffect(x:Int) {
var value = x
def modifyValue(newValue:Int):Unit = { value = newValue }
}
我的理解是,如果我们将它包装在如下的 State monad 中,它仍然会修改原始文件,使得包装它的意义没有实际意义。
case class State[S,+A](run: S => (A, S)) { // See footnote
// map, flatmap, unit, utility functions
}
val sideEffect = new SideEffect(20)
println(sideEffect.value) // Prints "20"
val stateMonad = State[SideEffect,Int](state => {
state.modifyValue(10)
(state.value,state)
})
stateMonad.run(sideEffect) // run the modification
println(sideEffect.value) // Prints "10" i.e. we have modified the original state
我能看到的唯一解决方案是复制该类并对其进行修改,但随着 SideEffect 的增长,这似乎计算成本很高。另外,如果我们想包装不实现 Cloneable 的 Java 类之类的东西,我们就很不走运了。
val stateMonad = State[SideEffect,Int](state => {
val newState = SideEffect(state.value) // Easier if it was a case class but hypothetically if one was, say, working with a Java library, one would not have this luxury
newState.modifyValue(10)
(newState.value,newState)
})
stateMonad.run(sideEffect) // run the modification
println(sideEffect.value) // Prints "20", original state not modified
我是不是用错了 State monad?如何包装一个副作用类而不必复制它,或者这是唯一的方法?
- 我在这里使用的 State monad 的实现来自本书,可能与 Scalaz 实现不同
【问题讨论】:
标签: scala state-monad