54 Stimmen

In welchem Sinne ist die IO-Monade rein?

Man hat mir die IO-Monade als eine Zustandsmonade beschrieben, bei der der Zustand "die reale Welt" ist. Die Befürworter dieses Ansatzes für IO argumentieren, dass dies IO-Operationen rein, d. h. referenziell transparent macht. Warum ist das so? Aus meiner Sicht scheint es, dass Code innerhalb der IO-Monade viele beobachtbare Seiteneffekte hat. Ist es nicht auch möglich, so ziemlich jede nicht-reine Funktion wie eine Funktion der realen Welt zu beschreiben? Können wir uns zum Beispiel malloc in C als eine Funktion vorstellen, die eine RealWorld und einem Int und gibt einen Zeiger und einen RealWorld , nur dass genau wie in der IO-Monade die RealWorld implizit ist?

Hinweis: Ich weiß, was eine Monade ist und wie sie verwendet wird. Bitte antworten Sie nicht mit einem Link zu einem beliebigen Monad-Tutorial, es sei denn, es geht speziell auf meine Frage ein.

4 Stimmen

Sie können meine Antwort hier nachlesen: stackoverflow.com/questions/3117583

61voto

mokus Punkte 3440

Ich glaube, die beste Erklärung, die ich gehört habe, wurde erst kürzlich in SO gegeben. IO Foo ist ein Rezept für die Erstellung eines Foo . Eine andere gängige, wörtlichere Formulierung ist, dass es sich um ein "Programm handelt, das eine Foo ". Sie kann (viele Male) ausgeführt werden, um eine Foo oder bei dem Versuch sterben. Die Ausführung des Rezepts/Programms ist das, was wir letztendlich wollen (warum sollten wir sonst eines schreiben?), aber das, was durch eine IO Aktion in unserem Code ist das Rezept selbst.

Dieses Rezept ist ein reiner Wert, und zwar in genau demselben Sinne wie ein String ist ein reiner Wert. Rezepte können auf interessante, manchmal erstaunliche Weise kombiniert und manipuliert werden, aber die vielen Möglichkeiten, wie diese Rezepte kombiniert werden können (mit Ausnahme der offenkundig nicht reinen unsafePerformIO , unsafeCoerce usw.) sind alle vollständig referenziell transparent, deterministisch und all diese schönen Dinge. Das sich ergebende Rezept hängt in keiner Weise vom Zustand anderer Dinge als der Rezepte ab, aus denen es aufgebaut wurde.

16voto

Dario Punkte 47246

Ist es nicht auch möglich, so ziemlich jede nicht-reine Funktion wie eine Funktion der realen Welt zu beschreiben? Können wir uns z.B. malloc in C als eine Funktion vorstellen, die eine RealWorld und eine Int annimmt und einen Zeiger und eine RealWorld zurückgibt, nur dass in der IO-Monade die RealWorld implizit ist?

Mit Sicherheit ...

Die ganze Idee der funktionalen Programmierung besteht darin, Programme als eine Kombination von kleine, unabhängige Berechnungen größere Berechnungen anzustellen.

Mit diesen unabhängig Berechnungen haben Sie viele Vorteile, die von prägnanten Programmen über effizienten und effizient parallelisierbaren Code, Faulheit bis hin zu der strengen Garantie reichen, dass die Kontrolle wie beabsichtigt fließt - ohne die Möglichkeit von Störungen oder der Verfälschung beliebiger Daten.

Jetzt - in einigen Fällen (wie IO) brauchen wir unreinen Code. Berechnungen mit solchen Operationen kann nicht unabhängig sein - sie könnten beliebige Daten einer anderen Berechnung verändern.

Der Punkt ist - Haskell ist immer rein , IO ändert daran nichts.

Unsere unreinen, nicht-unabhängigen Codes müssen also eine gemeinsame Abhängigkeit erhalten - wir müssen eine RealWorld . Für jede zustandsabhängige Berechnung, die wir durchführen wollen, müssen wir also diese RealWorld auf die wir unsere Änderungen anwenden - und jede andere zustandsabhängige Berechnung, die Änderungen sehen oder vornehmen möchte, muss die RealWorld auch.

Dies geschieht entweder explizit oder implizit durch die IO Monade ist irrelevant. Man baut ein Haskell-Programm als eine riesige Berechnung auf, die Daten transformiert, und ein Teil dieser Daten ist die RealWorld .

Sobald die erste main :: IO () aufgerufen wird, wenn Ihr Programm mit der aktuellen realen Welt als Parameter ausgeführt wird, wird diese reale Welt durch alle involvierten unsauberen Berechnungen getragen, genau wie Daten in einer State . Das ist es, was monadische >>= (binden) kümmert sich darum.

Und wo die RealWorld nicht bekommt (wie bei reinen Berechnungen oder ohne jegliche >>= -ing zu main ), gibt es keine Möglichkeit, etwas damit anzufangen. Und wo es する bekommen, das geschah durch rein funktionale Übergabe eines (impliziten) Parameters. Deshalb ist

let foo = putStrLn "AAARGH" in 42

absolut nichts bewirkt - und warum die IO Monade ist - wie alles andere auch - rein. Was innerhalb dieses Codes geschieht, kann natürlich unrein sein, aber es ist alles darin gefangen und hat keine Chance, mit nicht verbundenen Berechnungen zu interferieren.

10voto

yairchu Punkte 21749

Nehmen wir an, wir haben etwas wie:

animatePowBoomWhenHearNoiseInMicrophone :: TimeDiff -> Sample -> IO ()
animatePowBoomWhenHearNoiseInMicrophone
    levelWeightedAverageHalfLife levelThreshord = ...

programA :: IO ()
programA = animatePowBoomWhenHearNoiseInMicrophone 3 10000

programB :: IO ()
programB = animatePowBoomWhenHearNoiseInMicrophone 3 10000

Hier ist ein Gesichtspunkt:

animatePowBoomWhenHearNoiseInMicrophone ist eine reine Funktion in dem Sinne, dass ihre Ergebnisse für dieselbe Eingabe gelten, programA y programB sind genau dasselbe. Sie können tun main = programA o main = programB und es wäre genau dasselbe.

animatePowBoomWhenHearNoiseInMicrophone ist eine Funktion, die zwei Argumente erhält und eine Programmbeschreibung liefert. Die Haskell-Laufzeit kann diese Beschreibung ausführen, wenn Sie main oder auf andere Weise in die main über die Bindung.

Was ist IO ? IO ist eine DSL zur Beschreibung von imperativen Programmen, die in "Pure-Haskell"-Datenstrukturen und -Funktionen kodiert sind.

"complete-haskell" alias GHC ist eine Implementierung sowohl von "pure-haskell" als auch von einer imperativen Implementierung eines IO Decoder/Exekuter.

8voto

Tim Matthews Punkte 4923

Es läuft ganz einfach darauf hinaus weitgehende Gleichstellung :

Wenn Sie anrufen würden getLine zweimal, dann würden beide Aufrufe eine IO String die von außen jedes Mal genau gleich aussehen würden. Wenn Sie eine Funktion schreiben würden, die 2 IO String s und geben eine Bool um einen festgestellten Unterschied zwischen den beiden zu signalisieren, wäre es nicht möglich, anhand irgendwelcher beobachtbarer Eigenschaften einen Unterschied festzustellen. Es könnte keine andere Funktion fragen, ob sie gleich sind, und jeder Versuch, mit >>= muss auch etwas zurückgeben in IO die alle sind Äquall extern .

6voto

Tomer Ben David Punkte 7227

Ich lasse Martin Odersky diese Frage beantworten

Die IO-Monade macht eine Funktion nicht rein. Sie macht es nur offensichtlich dass sie unrein ist.

Klingt deutlich genug.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X