2012-04-12 1 views
8

Ich bin nicht so vertraut mit forall, aber diese Frage vor kurzem lesen: What does the `forall` keyword in Haskell/GHC do?Warum wird nicht standardmäßig (RankNTypes-Verwendung) standardmäßig angewendet?

In einem der Antworten ist dieses Beispiel:

{-# LANGUAGE RankNTypes #-} 
liftTup :: (forall x. x -> f x) -> (a, b) -> (f a, f b) 
liftTup liftFunc (t, v) = (liftFunc t, liftFunc v) 

Die Erklärung ist gut und ich verstehe, was forall hier tut. Aber ich frage mich, gibt es einen bestimmten Grund, warum dies nicht das Standardverhalten ist. Gibt es jemals eine Zeit, wo es nachteilig wäre?

Edit: Ich meine, gibt es einen Grund, warum die Foralls nicht standardmäßig eingefügt werden können?

+3

Fragen Sie, warum die Erweiterung nicht standardmäßig aktiviert ist oder warum '(x -> fx) -> (a, b) -> (fa, fb) 'wird nicht gleich behandelt wie' (forall x. x -> fx) -> (a, b) -> (fa, fb) '? Wenn es das letztere ist, können Sie die Logik angeben, nach der Sie den Compiler vorschlagen, sollte entscheiden, wo die 'Forall's einzufügen sind? – sepp2k

+0

Letzteres, und ich wüsste nicht, wo ich anfangen soll, überhaupt etwas zu diesem Thema vorzuschlagen! –

+0

Beachten Sie, dass der Typ '(x -> f x) -> (a, b) -> (f a, f b)' ziemlich nutzlos ist. Die Funktion kann das erste Argument nicht auf jedes Element des Tupels anwenden, daher muss das Ergebnis entweder '⊥' oder '(⊥, ⊥) 'sein. – hammar

Antwort

16

Nun, es ist nicht Teil des Haskell 2010-Standards, daher ist es standardmäßig nicht aktiviert und wird stattdessen als Spracherweiterung angeboten. Was die Gründe dafür betrifft, warum es nicht im Standard ist, sind Rang-n-Typen ziemlich viel schwieriger zu implementieren als der normale Rang-1-Typ-Standard, den Haskell hat; Sie werden auch nicht so oft benötigt, so dass der Ausschuss sich aus Gründen der Einfachheit und der Einfachheit der Sprache entschieden hat, sich nicht um sie zu kümmern.

Das bedeutet natürlich nicht, dass Rang-n-Typen nicht nützlich sind; Sie sind sehr, und ohne sie hätten wir keine wertvollen Werkzeuge wie die ST monad (die einen effizienten, lokal veränderbaren Zustand bietet - wie IO wo alles, was Sie tun können, ist IORef s). Aber sie fügen der Sprache einiges an Komplexität hinzu und können merkwürdiges Verhalten verursachen, wenn scheinbar sinnvolle Code-Transformationen angewendet werden. Zum Beispiel erlauben einige Rang-n-Typüberprüfer runST (do { ... }), aber lehnen runST $ do { ... } ab, obwohl die zwei Ausdrücke immer äquivalent ohne Rang-n-Typen sind. Ein Beispiel für das unerwartete (und manchmal ärgerliche) Verhalten, das es verursachen kann, finden Sie unter this SO question.

Wenn Sie wie sepp2k fragt, sind Sie stattdessen fragen, warum forall explizit hinzugefügt werden muss Unterschriften geben Sie die erhöhte Allgemeinheit zu bekommen, ist das Problem, dass (forall x. x -> f x) -> (a, b) -> (f a, f b) als (x -> f x) -> (a, b) -> (f a, f b) tatsächlich eine restriktivere Typ ist. Mit Letzterem können Sie beliebige Funktionen des Formulars x -> f x (für beliebige f und x) übergeben, aber mit ersteren muss die Funktion, die Sie übergeben, für allex arbeiten. So wäre zum Beispiel eine Funktion vom Typ String -> IO String ein zulässiges Argument für die zweite Funktion, aber nicht die erste; es müsste stattdessen den Typ a -> IO a haben. Es wäre ziemlich verwirrend, wenn letzterer automatisch in den ersten umgewandelt würde! Sie sind zwei sehr verschiedene Arten.

Es könnte mehr Sinn mit dem impliziten forall s explizit machen:

forall f x a b. (x -> f x)   -> (a, b) -> (f a, f b) 
forall f a b. (forall x. x -> f x) -> (a, b) -> (f a, f b) 
+0

Ich denke, ich muss das etwas mehr verdauen :) –

+0

Auch für den Polymorphismus zweiter und höherer Ordnung gibt es keinen allgemeingültigen Typ, '∀ b. (∀ a. A → b) → (b, b) 'ist nicht allgemeiner als' ∀ c d. (∀ a b. A → b) → (c, d) 'oder umgekehrt. Und während Typinferenz für Polymorphismus erster und zweiter Ordnung entscheidbar ist, ist es nicht für die dritte und höhere Ordnung. – Vitus

+0

@vitus - Können Sie eine Referenz für die Entscheidbarkeit von Polymorphismus zweiter Ordnung geben? Ich bin damit nicht vertraut. –

7

Ich vermute, dass höherrangige Typen nicht standardmäßig, weil they make type inference undecidable aktiviert sind. Aus diesem Grund müssen Sie auch bei aktivierter Erweiterung das Schlüsselwort forall verwenden, um einen höherrangigen Typ zu erhalten. GHC geht davon aus, dass alle Typen Rang 1 sind, sofern nicht ausdrücklich anders angegeben, um möglichst viele Typinformationen zu erhalten.

Anders gesagt, gibt es keinen allgemeinen Weg, um einen höherrangigen Typ (forall x. x -> f x) -> (a,b) -> (f a, f b) abzuleiten, so dass der einzige Weg, um diesen Typ zu erhalten, durch eine explizite Typ-Signatur ist.

Edit: per Vitus Kommentare oben, Rang-2 Typ Inferenz ist entscheidbar, aber höherrangiger Polymorphismus ist nicht. Daher ist diese Typensignatur technisch ableitbar (obwohl der Algorithmus komplexer ist).Ob die zusätzliche Komplexität des Erlaubens der polymorphen Typ-Inferenz des Rank-2 lohnend ist, ist fraglich ...