Hinweis: Diese Antwort basiert auf jüngsten Beobachtungen zu Levity-Diskussionen. Alles, was den Levity-Polymorphismus betrifft, ist derzeit nur in den GHC 8.0-Release-Kandidaten implementiert und kann sich daher ändern (siehe z. B. # 11471 ).
TL; DR : Es ist eine Möglichkeit, Funktionen gegenüber angehobenen und nicht angehobenen Typen polymorph zu machen, was mit regulären Funktionen nicht möglich ist. Zum Beispiel gibt der folgende Code keine Typprüfung mit regulären Polymorphismen ein, da Int#
hat Art #
, aber die Typvariablen in id
haben Art *
:
{-# LANGUAGE MagicHash #-}
import GHC.Prim
example :: Int# -> Int#
example = id
Couldn't match kind ‘*’ with ‘#’
When matching types
a0 :: *
Int# :: #
Expected type: Int# -> Int#
Actual type: a0 -> a0
In the expression: id
Beachten Sie, dass (->)
immer noch etwas Magie verwendet wird.
Bevor ich diese Frage beantworte, gehen wir einen Schritt zurück und gehen zu einer der am häufigsten verwendeten Funktionen ($)
.
Was ist ($)
der Typ? Nun, laut Hackage und dem Bericht ist es
($) :: (a -> b) -> a -> b
Das ist jedoch nicht 100% vollständig. Es ist eine bequeme kleine Lüge. Das Problem ist, dass polymorphe Typen (wie a
und b
) Art haben *
. (Bibliotheks-) Entwickler wollten jedoch ($)
nicht nur Typen mit Art verwenden *
, sondern auch solche #
, z
unwrapInt :: Int -> Int#
Während Int
hat Art *
(es kann unten sein), Int#
hat Art #
(und kann überhaupt nicht unten sein). Der folgende Code wird dennoch überprüft:
unwrapInt $ 42
Das sollte nicht funktionieren. Erinnern Sie sich an den Rückgabetyp von ($)
? Es war polymorph, und polymorphe Typen haben Art *
, nicht #
! Warum hat es funktioniert? Zuerst war es ein Fehler , und dann war es ein Hack (Auszug aus einer Mail von Ryan Scott auf der Mailingliste von ghc-dev):
Warum passiert das?
Die lange Antwort ist , dass vor der GHC 8.0, in der Art Unterschrift ($) :: (a -> b) -> a -> b
, b
war eigentlich nicht in der Art *
, sondern OpenKind
.
OpenKind
ist ein schrecklicher Hack, der es sowohl angehobenen (Art *
) als auch nicht angehobenen (Art #
) Typen erlaubt, ihn zu bewohnen, weshalb (unwrapInt $ 42)
Typechecks.
Was ist ($)
der neue Typ in GHC 8.0? Es ist
($) :: forall (w :: Levity) a (b :: TYPE w). (a -> b) -> a -> b
Um es zu verstehen, müssen wir uns Folgendes ansehen Levity
:
data Levity = Lifted | Unlifted
Jetzt können wir uns ($)
einen der folgenden Typen vorstellen, da es nur zwei Möglichkeiten gibt w
:
($) :: forall a (b :: TYPE Lifted). (a -> b) -> a -> b
($) :: forall a (b :: TYPE Unlifted). (a -> b) -> a -> b
TYPE
ist eine magische Konstante und definiert die Arten *
und #
als neu
type * = TYPE Lifted
type # = TYPE Unlifted
Die Quantifizierung über Arten ist ebenfalls ziemlich neu und Teil der Integration abhängiger Typen in Haskell .
Der Name Levity-Polymorphismus kommt von der Tatsache, dass Sie jetzt polymorphe Funktionen sowohl über angehobene als auch über nicht angehobene Typen schreiben können, was mit den vorherigen Einschränkungen des Polymorphismus nicht erlaubt / möglich war. OpenKind
Gleichzeitig wird auch der Hack beseitigt. Es geht wirklich "nur" darum, mit beiden Arten von Arten umzugehen.
Übrigens sind Sie mit Ihrer Frage nicht allein. Sogar Simon Peyton Jones sagte, dass eine Levity-Wiki-Seite erforderlich sei , und Richard E. (der aktuelle Implementierer) erklärte, dass die Wiki-Seite ein Update des aktuellen Prozesses benötigt.
Verweise
($) :: forall (w1 w2 :: Levity) (a :: TYPE w1) (b :: TYPE w2). (a -> b) -> a -> b
, dh warum($)
soll es nicht mit Funktionen mit nicht aufgehobenen Argumenten verwendbar sein?RuntimeRep
(ersetztLevity
).