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?
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:
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:
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 .
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
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%Tags und Links haskell state-monad