Ich habe endlich gelernt, wie man Monaden benutzt (weiß nicht, ob ich sie verstehe ...), aber mein Code ist nie sehr elegant. Ich schätze aus mangelnder Griffigkeit, wie all diese Funktionen auf Control.Monad
wirklich helfen können. Also dachte ich, es wäre schön, in einem bestimmten Code mit der State-Monade nach Tipps zu fragen.Tipps für eleganter Code mit Monaden?
Das Ziel des Codes ist es, viele Arten von zufälligen Wanderungen zu berechnen, und es ist etwas, was ich vor etwas komplizierter zu tun versuche. Das Problem ist, dass ich zwei Stateful Berechnungen zur gleichen Zeit haben, und ich würde gerne wissen, wie sie mit Eleganz zu komponieren:
- Die Funktion, die den Zufallszahlengenerator aktualisiert etwas vom Typ
Seed -> (DeltaPosition, Seed)
- Die Funktion, die die Position des Random Walker aktualisiert, ist etwas vom Typ
DeltaPosition -> Position -> (Log, Position)
(wobeiLog
nur eine Möglichkeit für mich ist, zu berichten, was die aktuelle Position des Random Walker ist).
Was ich getan habe, ist dies:
ich eine Funktion haben diese beiden Stateful Berechnungen zu komponieren:
composing :: (g -> (b, g)) -> (b -> s -> (v,s)) -> (s,g) -> (v, (s, g))
composing generate update (st1, gen1) = let (rnd, gen2) = generate gen1
(val, st2) = update rnd st1
in (val, (st2, gen2))
und dann habe ich es in eine Funktion drehen, dass die Staaten zusammensetzen:
stateComposed :: State g b -> (b -> State s v) -> State (s,g) v
stateComposed rndmizer updater = let generate = runState rndmizer
update x = runState $ updater x
in State $ composing generate update
Und dann habe ich die einfachste Sache, zum Beispiel, ein zufälliger Walker, der nur eine zufällige Zahl an seine aktuelle Position summieren wird:
update :: Double -> State Double Double
update x = State (\y -> let z = x+y
in (z,z))
generate :: State StdGen Double
generate = State random
rolling1 = stateComposed generate update
und eine Funktion dies wiederholt zu tun:
rollingN 1 = liftM (:[]) rolling1
rollingN n = liftM2 (:) rolling1 rollings
where rollings = rollingN (n-1)
Und dann, wenn ich diese laden in ghci
und laufen:
*Main> evalState (rollingN 5) (0,mkStdGen 0)
[0.9872770354820595,0.9882724161698186,1.9620425108498993,2.0923229488759123,2.296045158010918]
ich bekommen, was ich will, was eine ist Liste der vom Random Walker belegten Positionen. Aber ... Ich denke, es muss einen eleganteren Weg geben, dies zu tun. Ich habe zwei Fragen:
Kann ich diese Funktionen in einer „monadischen“ Art und Weise neu zu schreiben, mit cleveren Funktionen von
Control.Monad
?Gibt es ein allgemeines Muster für die Kombination solcher Zustände, die verwendet werden können? Hat das etwas mit Monad-Transformatoren oder etwas ähnlichem zu tun?
By the way, ist es eine gute Idee, um das 'State' Daten Konstruktor zu vermeiden, verwenden, da in' mtl' Nachfolgern ('Monaden-fd'),' State ist definiert als "StateT" und daher existiert der "State" -Datenkonstruktor nicht. –
@TravisBrown Tatsächlich ist 'monads-fd' für 'mtl' veraltet. (Erkennen, dass Ihr Kommentar 5 Jahre alt ist.) – crockeea