2017-05-29 7 views
0

Nachdem ich Kapitel 6 von Functional Programming in Scala gelesen habe und versuche, die Zustands-Monade zu verstehen, habe ich eine Frage bezüglich der Umhüllung einer Nebeneffekt-Klasse.Einpacken einer Klasse mit Nebenwirkungen

Angenommen, ich habe eine Klasse, die sich selbst irgendwie modifiziert.

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

Mein Verständnis ist, dass, wenn wir dies in einem Staat Monade, wie unten gewickelt, es wäre immer noch das Original macht den Punkt der Verpackung es strittig zu ändern.

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 

Die einzige Lösung dieses Problems, die ich sehen kann, ist eine Kopie der Klasse zu machen und das ändern, aber das scheint rechnerisch teuer als Nebeneffekt wächst. Und wenn wir etwas wie eine Java-Klasse umhüllen wollten, die Cloneable nicht implementiert, hätten wir kein Glück.

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 

Benutze ich die State-Monade falsch? Wie würde man eine seiteneffektive Klasse umhüllen, ohne sie kopieren zu müssen, oder ist das der einzige Weg?

  • Die Umsetzung für den Staat Monade Ich bin hier stammt aus dem Buch mit, und könnte von Scalaz Implementierung

Antwort

2

Sie können nichts mit veränderlichem Objekt unterscheidet Mutation in einigen außer versteckt Verpackung. Daher wird der Umfang des Programms, das beim Testen mehr Aufmerksamkeit erfordert, viel kleiner sein. Ihre erste Probe ist gut genug. Nur einen Moment. Es wäre besser, die äußere Referenz überhaupt zu verstecken. Stattdessen stateMonad.run(sideEffect) verwenden Sie etwas wie stateMonad.run(new SideEffect(20)) oder

def initState: SideEffect = new SideEffect(20) 
val (state, value) = stateMonad.run(initState) 
Verwandte Themen