2015-03-11 4 views
5

Ich habe mit Applicative Instanzen gespielt, um herauszufinden, wie sie funktionieren. Allerdings verstehe ich dieses Verhalten ehrlich nicht.Wie druckt GHCi teilweise angelegte Werte aus "pure"?

Wenn ich meinen eigenen Datentyp definiere, dann wende ich pure ohne weitere Argumente an, es wird nichts ausgedruckt, aber es kommt zu Fehlern, wenn ich versuche, etwas auf das Ergebnis anzuwenden.

ghci> data T = A 
ghci> pure A 
ghci> pure A 0 

<interactive>:21:1: 
    No instance for (Show T) arising from a use of ‘print’ 
    In a stmt of an interactive GHCi command: print it 

Wenn ich jedoch T eine Instanz Show machen, dann wird A in beiden Fällen ausgedruckt.

ghci> data T = A deriving (Show) 
ghci> pure A 
A 
ghci> pure A 0 
A 

Was wirklich nicht verstehen ist, ich, wie pure A Wert sein kann, die unterschiedlich zwischen den beiden Fällen gedruckt wird. Ist nicht pure A teilweise angewendet?

Ich verstehe, warum pure A 0 Fehler im ersten Beispiel Aufruf und nicht in den zweiten, den Sinn für mich macht. Das verwendet die ((->) r) Instanz von Applicative, so dass es einfach eine Funktion liefert, die immer A zurückgibt.

Aber wie ist pure mit nur einem Wert instanziiert, wenn der Typ des applicative selbst noch nicht bekannt? Außerdem, wie kann GHC diesen Wert möglicherweise drucken?

Antwort

14

GHCi ist ein bisschen eigenartig. Insbesondere dann, wenn Sie einen Ausdruck an der Eingabeaufforderung eingeben, versucht er es auf zwei verschiedene Arten zu interpretieren, um:

  1. Als IO Aktion auszuführen.
  2. Als Wert zum Ausdrucken.

Seit IO ist Applicative, es pure A als IO Wirkung erzeugt wird etwas vom Typ T interpretiert. Es führt diese Aktion aus (was nichts tut), und da das Ergebnis nicht in Show ist, wird nichts ausgedruckt. Wenn Sie T eine Instanz von Show machen, dann druckt es das Ergebnis für Sie aus.

Wenn Sie pure A 0 schreiben, sieht GHCi dies:

pure :: Applicative f => a -> f a 
pure A :: Applicative f => f T 

Und da Sie pure A-0 anwenden, pure A muss eine Funktion a->b für einige Arten a und b sein und a0 enthalten.

(Num a, Applicative f) => f T ~ (a -> b) 

(Beachten Sie, dass x ~ y bedeutet, dass x und y Unify-sie die gleiche Art haben, gemacht werden können.)

So wir f ~ ((->) a) und T ~ b, so in der Tat müssen GHC dass folgert, in dieser Zusammenhang

pure A :: Num a => ((->) a) T 

Welche können wir umschreiben als

pure A :: Num a => a -> T 

Nun, (->) a ist eine Instanz von Applicative, nämlich "Leser", also das ist in Ordnung. Wenn wir pure A auf 0 anwenden, erhalten wir etwas vom Typ T, nämlich A. Diese kann nicht interpretiert werden als eine IO Aktion, natürlich, wenn also T keine Instanz von Show ist, wird GHCi beschweren.

7

Wenn Sie einen Wert von mehrdeutigem Typ der GHCi Aufforderung geben zu bewerten, versucht es, die Art auf verschiedene Weise auf dem Standard. Insbesondere wird versucht, ob ein Typ IO a passt, falls Sie eine IO-Aktion ausführen möchten (siehe the GHC manual). In Ihrem Fall ist pure A standardmäßig der Typ IO T. Auch:

Darüber hinaus GHCi wird das Ergebnis der I/O-Aktion drucken, wenn (und nur dann):

  • Der Ergebnistyp eine Instanz von Show ist.
  • Der Ergebnistyp ist nicht ().
+0

Warum speziell 'IO'? Ist das nur ein willkürlicher Standard? –

+1

@AlexisKing, ist es ein praktischer Standard für die Art von interaktiver Entwicklung, die Leute mit GHCi machen. In GHCi gibt es kein 'main', und es wäre ärgerlich, einen speziellen Interpreter-Befehl aufrufen zu müssen, um eine' IO'-Aktion auszuführen. – dfeuer

+1

Mit 'IO'-Aktionen und nur' IO'-Aktionen führt * sie * sie aus und bewertet sie, so dass sie speziell behandelt werden müssen. Dass es auch generische'Applicative/Monad'-Aktionen darauf setzt, ist wahrscheinlich nur ein netter Nebeneffekt, obwohl dieser explizit im Handbuch erwähnt wird. –