Frage

Ich habe eine Funktion:

test :: String -> State String String
test x = 
    get >>= \test ->
    let test' = x ++ test in
    put test' >>
    get >>= \test2 -> put (test2 ++ x) >>
    return "test"

Ich kann ziemlich viel verstehen, was in dieser Funktion geht weiter, und ich fange an den Dreh Monaden zu bekommen. Was ich nicht verstehe, ist, wie, wenn ich laufe dies:

runState (test "testy") "testtest"

die ‚get‘ Funktion in ‚Test‘ bekommt irgendwie den Ausgangszustand „testtest“. Kann jemand diese nach unten brechen und es mir erklären?

Ich schätze alle Antworten!

War es hilfreich?

Lösung

Ich war ursprünglich werde dies als Kommentar veröffentlichen, aber wir entschieden uns ein wenig mehr zu erklären.

Genau genommen get nicht „nehmen“ ein Argument. Ich denke, eine Menge, was los ist maskiert durch das, was Sie nicht sehen werden - die Instanzdefinitionen des Staates Monade

.

get ist eigentlich eine Methode der MonadState Klasse. Der Staat Monade ist eine Instanz MonadState, die folgende Definition von get Bereitstellung:

get = State $ \s -> (s,s)

Mit anderen Worten, gibt get nur eine sehr grundlegende staatliche Monade (nicht vergessen, dass eine Monade als „Wrapper“ gedacht werden kann für eine Berechnung), wobei jeder Eingang s in die Berechnung ein Paar s als Ergebnis zurück .

Das nächste, was wir brauchen, zu betrachten ist >>=, der Staat definiert so:

m >>= k  = State $ \s -> let
    (a, s') = runState m s
    in runState (k a) s'

Also, >>= wird eine neue Berechnung erhalten, die nicht berechnet werden, bis es einen Anfangszustand wird (dies gilt für alle staatlichen Berechnungen, wenn sie in ihrer „verpackt“ Form sind). Das Ergebnis dieser neuen Berechnung wird durch die Anwendung erreicht, was auch immer auf der rechten Seite des >>= auf das Ergebnis der Ausführung die Berechnung ist, der auf der linken Seite war. (Das ist ein ziemlich verwirrend Satz, der eine zusätzliche Lese oder zwei benötigen.)

Ich habe es sehr nützlich „desugar“ alles gefunden, die vor sich geht. Dadurch nimmt so viel mehr schreiben, sondern die Antwort auf Ihre Frage stellen (wo get wird immer aus) sehr deutlich. Beachten Sie, dass die folgenden sollte psuedocode in Betracht gezogen werden ...

test x =
    State $ \s -> let
        (a,s') = runState (State (\s -> (s,s))) s  --substituting above defn. of 'get'
        in runState (rightSide a) s'
        where 
          rightSide test = 
            let test' = x ++ test in
            State $ \s2 -> let
            (a2, s2') = runState (State $ \_ -> ((), test')) s2  -- defn. of 'put'
            in runState (rightSide2 a2) s2'
          rightSide2 _ =
            -- etc...

Das sollte es offensichtlich machen, dass das Endergebnis unserer Funktion eine neue staatliche Berechnung ist, die einen Anfangswert (s) muss den Rest des Materials möglich zu machen. Sie versorgen s als "testtest" mit Ihrem runState Anruf. Wenn Sie s in dem obigen Pseudo-Code „testtest“ ersetzen, werden Sie sehen, dass das erste, was passiert ist, dass wir get mit „testtest“ als ‚Anfangszustand‘ laufen. Dies ergibt ("testtest", "testtest") und so weiter.

Also das ist, wo get Ihren Ausgangszustand „testtest“ bekommt. Hoffe, das hilft!

Andere Tipps

Es könnte Ihnen helfen, was die State Typkonstruktor einen tieferen Blick zu nehmen, um wirklich ist und wie runState nutzt. In GHCi:

Prelude Control.Monad.State> :i State
newtype State s a = State {runState :: s -> (a, s)}
Prelude Control.Monad.State> :t runState
runState :: State s a -> s -> (a, s)

State zwei Argumente: den Typ des Staates, und das zurückgegebene Typ. Es ist implementiert als eine Funktion der Ausgangszustand zu nehmen und einen Rückgabewert und den neuen Zustand erhalten wird.

runState nimmt eine solche Funktion, die anfängliche Eingabe und (höchstwahrscheinlich) gilt nur einen zum anderen das (Ergebnis Zustand) Paar abgerufen werden.

Ihre test Funktion ist eine große Komposition von State-Typ-Funktionen, die jeweils einen Zustand Eingang zu nehmen und einen (Ergebnis Zustand) Ausgang ergibt, in miteinander in eine Art und Weise eingesteckt, den Sinn für Ihr Programm macht. All runState tut, ist sie mit einem Punkt Zustand Start liefern.

In diesem Zusammenhang get ist einfach eine Funktion, Zustand als eine Eingabe nimmt, und gibt einen (Folge-Zustand) ausgegeben, so dass das Ergebnis der Eingangszustand ist, und der Zustand unverändert ist (der Ausgangszustand ist der Eingangszustand ). Mit anderen Worten, get s = (s, s)

Wenn man durch Kapitel 8 ( "Functional Parser") von Graham Hutton Programmierung in Haskell mehrmals, bis würde ich verstehe es richtig, von einem Sprung auf dem Tutorial gefolgt Alles über Monaden , machte diesen Klick für mich.

Das Problem mit Monaden ist, dass sie für mehrere Dinge sehr nützlich sind, dass diejenigen von uns, von dem üblichen Programmier Hintergrund kommen finden ganz unähnlich. Es dauert einige Zeit, dass der Steuerfluss und Handhabung Zustand ist nicht nur ähnlich genug, um zu erkennen, dass sie durch den gleichen Mechanismus gehandhabt werden können, sind aber, wenn man weit genug zurück Schritt, die gleiche Sache.

Eine Epiphanie kam, als ich Kontrollstrukturen in C (for und while, etc.) unter Berücksichtigung, und ich erkennen, dass bei weitem der häufigste Kontrollstruktur einfach vor dem anderes eine Erklärung anzog. Es dauerte ein Jahr von Haskell studieren, bevor ich erkennen, dass, dass selbst eine Kontrollstruktur war.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top