Haskell hilft, diesen State Monad Code zu verstehen: Wo ist RunState definiert?

8

Ich bin neu bei Haskell und versuche, Monaden zu verstehen. Ich gehe durch diesen Code Setzen Sie es hier zur schnellen Referenz

%Vor%

Ich habe nicht verstanden, wo die Funktion runState definiert ist. Es scheint, dass sein Typ in newtype State s a = State { runState :: s -> (a,s) } angegeben ist. Der verwirrendste Teil ist, dass dieser Code ohne Fehler kompiliert wird.

Wo ist runState definiert? Wo ist der Code?

    
mntk123 13.09.2015, 06:40
quelle

2 Antworten

6

Was Ihnen anscheinend fehlt, ist die Funktionalität, die von Datensatzsyntax bereitgestellt wird. In Haskell gibt es mehrere Möglichkeiten, einen Datentyp zu definieren. Sie sind wahrscheinlich mit folgenden Aussagen vertraut:

%Vor%

wo ein Typ MyType definiert ist, der ein Summentyp ist (d. h. jeder Wert dieses Typs hat beide die Felder String und Int gefüllt). Wenn wir mit diesem Typ arbeiten möchten, möchten wir vielleicht die Komponenten String und Int separat anzeigen, also würden wir hierfür Accessor-Funktionen definieren:

%Vor%

Für große Datentypen (mit vielen Feldern) kann das sehr mühsam werden, und das Schreiben dieser Art von Funktion ist im Allgemeinen sehr üblich: Oft haben wir einen einfachen Typ, bei dem ein Konstruktor den Inhalt umschließt, und wir wollen einen bequemen Weg dazu Zugriff auf diesen Inhalt in seinem "eigenen" Typ (dh ohne den Wrapper).

Da dieser Wunsch, auf Felder zuzugreifen, so häufig ist, bietet Haskell eine Datensatzsyntax. Wenn Sie die Datensatzsyntax verwenden, benennen Sie im Wesentlichen die Felder innerhalb eines Datentyps, und die Funktionen zum Extrahieren der Werte in diesen Feldern werden automatisch generiert. So könnten wir unseren Datentyp von früher neu definieren:

%Vor%

und Haskell würden automatisch die Accessor-Funktionen myLabel :: MyType' -> String und myNum :: MyType' -> Int generieren. Diese Funktionen haben dann die gleiche Funktionalität wie die zuvor definierten Funktionen getLabel und getNum .

Wenn wir den Typ State als Beispiel genommen hätten, hätten wir ihn wie folgt definieren können:

%Vor%

und schrieb eine Funktion, um auf den Inhalt zuzugreifen:

%Vor%

was uns erlauben würde, den State' "wrapping" um unseren Wert herum zu entfernen. Dies ist jedoch weniger praktisch als die Verwendung der Datensatzsyntax, die in Ihrem Beispiel verwendet wird: Der im State -Wrapper gespeicherte Wert erhält den Feldnamen runState , und Haskell generiert die Accessor-Funktion, weshalb der Code kompiliert und ohne ausgeführt wird Probleme. runState macht dann grundsätzlich dasselbe wie getStateFun .

Das wird auch im Abschnitt "Record syntax" in dieses Kapitel von ganz deutlich erklärt Lernen Sie ein Haskell für großes Gutes .

    
Sam van Herwaarden 13.09.2015, 12:27
quelle
10

Ja, Sie haben recht, es ist hier definiert:

%Vor%

im Grunde von einer Definition wie folgt erhalten Sie zwei Funktionen kostenlos:

  • State :: (s -> (a,s)) -> State s a der Konstruktor (benannt wie der Typ) - hier können Sie umbrechen in einer Funktion in newtype
  • und runState :: State s a -> (s -> (a,s)) (gleich State s a -> s -> (a,s) ) innerhalb der Record-Syntax - dies wird die umgebrochene Funktion aus dem ersten Argument nehmen und sie auf das zweite Argument anwenden (oder den Funktion zurück - Curry ermöglicht es uns, mit beiden Interpretationen gut zu arbeiten)

In gewisser Weise schreibt Sie seinen Code, wenn Sie einen neuen Wert für State s a erstellen - er nimmt diesen Wert, ruft den Inhalt auf und wendet ihn an.

Also, zum Beispiel, wenn Sie

tun %Vor%

auf Ihre Frage - soweit ich es verstehe - ist die Record-Syntax gleich:

%Vor%     
Carsten 13.09.2015 06:45
quelle

Tags und Links