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)
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
Letzteres, und ich wüsste nicht, wo ich anfangen soll, überhaupt etwas zu diesem Thema vorzuschlagen! –
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