2010-05-11 7 views
9

Ich verstehe die genaue Algebra und Theorie hinter Haskells Monaden nicht. Wenn ich jedoch über die funktionale Programmierung im Allgemeinen nachdenke, habe ich den Eindruck, dass der Zustand modelliert wird, indem ein Anfangszustand genommen wird und eine Kopie davon erzeugt wird, um den nächsten Zustand darzustellen. Dies ist wie wenn eine Liste an eine andere angehängt wird; Keine der Listen wird geändert, aber eine dritte Liste wird erstellt und zurückgegeben.Können Haskells Monaden als versteckte Zustandsparameter verwendet und zurückgegeben werden?

Ist es daher zulässig, monadische Operationen als implizites Nehmen eines ursprünglichen Zustandsobjekts als Parameter und implizites Zurückgeben eines endgültigen Zustandsobjekts zu betrachten? Diese Zustandsobjekte würden verborgen sein, so dass sich der Programmierer nicht darum kümmern und kontrollieren muss, wie er darauf zugreift. Der Programmierer würde also nicht versuchen, das Objekt zu kopieren, das den IO-Stream darstellt, wie es vor zehn Minuten war.

Mit anderen Worten, wenn wir diesen Code haben:

main = do 
    putStrLn "Enter your name:" 
    name <- getLine 
    putStrLn ("Hello " ++ name) 

... ist es OK der IO Monade zu denken und die „do“ Syntax wie diese Art von Code, der?

putStrLn :: IOState -> String -> IOState 
getLine :: IOState -> (IOState, String) 
main :: IOState -> IOState 

-- main returns an IOState we can call "state3" 
main state0 = putStrLn state2 ("Hello " ++ name) 
    where (state2, name) = getLine state1 
     state1 = putStrLn state0 "Enter your name:" 

Antwort

18

Nein, das ist nicht, was Monaden im Allgemeinen tun. Allerdings ist Ihre Analogie in der Tat genau richtig in Bezug auf den Datentyp State s a, die ein Monad ist. State ist wie folgt definiert:

newtype State s a = State { runState :: s -> (a, s) } 

...Dabei ist die Typvariable s der Statuswert und a ist der von Ihnen verwendete "reguläre" Wert. Ein Wert in der "State Monade" ist also nur eine Funktion von einem Anfangszustand zu einem Rückgabewert und Endzustand. Der monadische Stil, wie er auf State angewendet wird, tut nichts weiter, als einen Zustandswert automatisch durch eine Folge von Funktionen einzufädeln.

Die ST Monade ist oberflächlich ähnlich, nutzt aber magische Berechnungen mit realen Nebenwirkungen zu erlauben, aber nur so, dass die Nebenwirkungen nicht von außen bestimmten Verwendungen von ST beobachtet werden können.

Die IO Monade ist im Wesentlichen ein ST Monade „mehr Magie“ gesetzt, mit Nebenwirkungen, die die Außenwelt berühren und nur einen einzigen Punkt, wo IO Berechnungen ausgeführt werden, nämlich den Einstiegspunkt für das gesamte Programm. Auf einer konzeptionellen Ebene kann man sich immer noch vorstellen, dass es einen "state" -Wert durch Funktionen fädelt, wie es regulär State tut.

Allerdings haben andere Monaden nicht unbedingt etwas mit Threading-Status oder Sequenzierungsfunktionen oder was auch immer zu tun. Die Operationen, die für etwas benötigt werden, um eine Monade zu sein, sind unglaublich allgemein und abstrakt. Wenn Sie beispielsweise Maybe oder Either als Monaden verwenden, können Sie Funktionen verwenden, die möglicherweise Fehler zurückgeben, wobei die Behandlung im monadischen Stil bei einem Fehler aus der Berechnung entfernt wird, genauso wie State einen Statuswert verarbeitet. Die Verwendung von Listen als Monade gibt Ihnen nondeterminism, so dass Sie gleichzeitig Funktionen auf mehrere Eingänge anwenden und alle möglichen Ausgaben sehen können, wobei der monadische Stil die Funktion automatisch auf jedes Argument anwendet und alle Ausgaben sammelt.

+0

Ah ja, ich vergaß die Maybe und Entweder Monaden. – AJM

+0

@AJM Es ist * eine gültige Möglichkeit, über IO zu denken. Du kannst dir vorstellen, dass IO eine staatliche Monade ist, mit der ganzen Realität als "s". – PyRulez

4

Nicht Monaden im Allgemeinen, aber für die IO-Monade, ja - in der Tat, die Art IO a wird oft als Funktionstyp RealWorld -> (RealWorld, a) definiert. In dieser Ansicht ist der entartete Typ von putStrLn also String -> RealWorld -> (RealWorld,()) und getChar ist RealWorld -> (RealWorld, Char) - und wir wenden ihn nur teilweise an, wobei der monadische bind sich darum kümmert, ihn vollständig auszuwerten und die RealWorld herumzureichen. (Die ST-Bibliothek von GHC enthält tatsächlich einen sehr realen RealWorld Typ, obwohl es als "tief magisch" und nicht für den tatsächlichen Gebrauch beschrieben wird.)

Es gibt viele andere Monaden, die diese Eigenschaft jedoch nicht haben. Es gibt keine RealWorld, die zum Beispiel mit den Monaden [1,2,3,4] oder Just "Hello" herumgereicht wird.

+0

Der wirkliche Grund, dass sie 'RealWorld' sagen, ist nicht für den tatsächlichen Gebrauch, sie wollen nicht, dass Leute etwas tun wie' setPresident RealWorld "pyrulez" oder so etwas (sie wollen die ganze Macht für sich). – PyRulez

8

Ist es daher zulässig, monadische Operationen als implizites Nehmen eines ursprünglichen Zustandsobjekts als Parameter und implizites Zurückgeben eines endgültigen Zustandsobjekts zu betrachten?

Dies scheint ein gemeinsamer Knackpunkt für das Lernen Monaden zu sein, dh, eine einzige magischen Monade Ursuppe Berechnungen, um herauszufinden, wie für die Darstellung von Stateful-Berechnungen gleichzeitig nützlich ist, die, nicht deterministische Berechnungen versagen können, Ausnahmen Fortsetzungen, Sequenzierungseffekte und so weiter.

Threading-Status durch eine Sequenz von Stateful-Berechnungen ist ein einziges Beispiel einer Operation, die die Monad-Gesetze erfüllt.

Sie sind richtig bei der Beobachtung, dass die State und IO Monaden sind eng miteinander verwandt, aber Ihre Analogie wird auseinander fallen, wenn Sie Einfügen versuchen, sagen wir, die Liste Monade.

0

Ich bevorzuge es, über Monaden als Objekte zu denken, die verzögerte Aktionen (runXXX, main) mit Ergebnis darstellen, die entsprechend diesem Ergebnis kombiniert werden können.

return "somthing" 
actionA >>= \x -> makeActionB x 

Und diese Aktion nicht unbedingt State-Full. I.e. Sie können über Monad der Funktion Konstruktion wie folgt denken:

instance Monad ((->) a) where 
    m >>= fm = \x -> fm (m x) x 
    return = const 

sqr = \x -> x*x 
cube = \x -> x*x*x 

weird = do 
    a <- sqr 
    b <- cube 
    return (a+b) 
3

Absolut nicht. Dies ist nicht, was Monaden im Allgemeinen sind. Sie können Monaden verwenden, um Daten implizit weiterzuleiten, aber das ist nur eine Anwendung. Wenn Sie dieses Modell von Monaden verwenden, dann werden Sie eine Menge der wirklich coolen Dinge vermissen, die Monaden tun können.

Denken Sie stattdessen über Monaden als Teile von Daten, die eine Berechnung darstellen. Zum Beispiel gibt es einen Sinn, bei dem die implizite Weitergabe von Daten nicht rein ist, weil reine Sprachen darauf bestehen, dass Sie alle Argumente und Rückgabetypen explizit angeben. Wenn Sie also Daten implizit weitergeben möchten, können Sie Folgendes tun: Definieren Sie einen neuen Datentyp, der eine Darstellung von etwas Unreines ist, und schreiben Sie dann ein Stück Code, um damit zu arbeiten.

Ein extremes Beispiel (nur ein theoretisches Beispiel, das ist unwahrscheinlich, dass Sie dies tun möchten) wäre das: C ermöglicht unreine Berechnungen, so dass Sie einen Typ definieren könnten, der einen Teil von C-Code darstellt. Sie können dann einen Interpreter schreiben, der eine dieser C-Strukturen übernimmt und interpretiert. Alle Monaden sind so, obwohl normalerweise viel einfacher als ein C-Interpreter. Aber diese Ansicht ist mächtiger, weil sie auch die Monaden erklärt, die nicht darum gehen, den verborgenen Zustand zu umgehen.

Sie sollten wahrscheinlich auch versuchen, der Versuchung zu widerstehen, IO als einen verborgenen Weltzustand zu sehen. Die interne Implementierung von IO hat nichts damit zu tun, wie Sie über IO denken sollten. Bei der IO-Monade handelt es sich um die Erstellung von Repräsentationen der I/O, die Sie ausführen möchten. Sie geben eine dieser Repräsentationen an das Haskell-Laufzeitsystem zurück und es liegt an diesem System, Ihre Repräsentation wie gewünscht zu implementieren.

Jedes Mal, wenn Sie wollen, etwas zu tun, und Sie können nicht sehen, wie direkt es in einer reinen Art und Weise zu implementieren, aber man kann sehen, wie eine reine Datenstruktur aufzubauen, um beschreiben wollen Sie wollen, Sie kann eine Anwendung für eine Monade haben, besonders wenn deine Struktur von Natur aus ein Baum ist.

Verwandte Themen