2017-05-29 5 views
0

Functional Programming in Scalaの第6章を読んで状態モナドを理解しようとしたら、副作用クラスをラップすることについて質問があります。副作用のあるクラスをラップする

いいえ、私は多分自分自身を変更するクラスがあります。

class SideEffect(x:Int) { 
    var value = x 
    def modifyValue(newValue:Int):Unit = { value = newValue } 
} 

私の理解では、私たちは以下のようStateモナドでこれを包んだ場合、それはまだ議論の余地がそれを包むのポイントを作る元を変更するだろうということです。

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モナドのための実装は本からなり、Scalazの実装は異なる場合がありますあなたは、いくつかの変異を隠す以外可変オブジェクトと何もできない

答えて

2

ラッパー。したがって、テストでもっと注意を必要とするプログラムの範囲ははるかに小さくなります。あなたの最初のサンプルは十分です。一瞬だけ。外部参照をまったく隠す方がよいでしょう。代わりにstateMonad.run(sideEffect)のようなものを使用してください。stateMonad.run(new SideEffect(20))または

def initState: SideEffect = new SideEffect(20) 
val (state, value) = stateMonad.run(initState) 
関連する問題