Ich bin mir ziemlich sicher, dass jeder mit allgemeinen Methoden der Form vertraut ist:
T DoSomething<T>(T item)
Diese Funktion wird auch als parametrisch polymorph (PP) bezeichnet, insbesondere als PP mit Rang 1 .
Nehmen wir an, diese Methode kann mit einem Funktionsobjekt der Form dargestellt werden:
<T> : T -> T
Dies <T>
bedeutet, dass ein Typparameter verwendet wird und T -> T
dass ein Typparameter verwendet wird T
und ein Wert desselben Typs zurückgegeben wird.
Dann wäre das Folgende eine Rang-2-PP-Funktion:
(<T> : T -> T) -> int
Die Funktion akzeptiert selbst keine Typparameter, sondern eine Funktion, die einen Typparameter akzeptiert. Sie können dies iterativ fortsetzen, indem Sie die Verschachtelung immer tiefer machen und PP von immer höherem Rang erhalten.
Diese Funktion ist unter Programmiersprachen sehr selten. Sogar Haskell lässt dies standardmäßig nicht zu.
Ist es nützlich? Kann es Verhalten beschreiben, die sonst schwer zu beschreiben sind?
Was bedeutet es auch, dass etwas anregend ist ? (in diesem Kontext)
let sdff = (g : (f : <T> (e : T) => void) => void) => {}
Antworten:
Im Allgemeinen verwenden Sie einen höherrangigen Polymorphismus, wenn der Angerufene den Wert eines Typparameters anstelle des Aufrufers auswählen soll . Beispielsweise:
Jede Funktion
g
, die ich an diese übergebe,f
muss in der Lage sein, mirInt
einen Wert von einem Typ zu geben, von dem das einzige, wasg
über diesen Typ weiß, ist, dass er eine Instanz von hatShow
. Das sind also koschere:Das sind aber nicht:
Eine besonders nützliche Anwendung besteht darin, das Scoping von Typen zu verwenden, um das Scoping von Werten zu erzwingen . Angenommen, wir haben ein Objekt vom Typ
Action<T>
, das eine Aktion darstellt, die wir ausführen können, um ein Ergebnis vom Typ zu erzeugenT
, z. B. eine Zukunft oder einen Rückruf.Angenommen, wir haben auch eine
Action
, dieResource<T>
Objekte zuordnen kann:Wir möchten sicherstellen, dass diese Ressourcen nur in dem Bereich verwendet werden, in dem
Action
sie erstellt wurden, und nicht zwischen verschiedenen Aktionen oder verschiedenen Läufen derselben Aktion aufgeteilt werden, damit Aktionen deterministisch und wiederholbar sind.Um dies zu erreichen, können wir höherrangige Typen verwenden, indem wir
S
denResource
undAction
-Typen einen Parameter hinzufügen , der völlig abstrakt ist - er repräsentiert den „Geltungsbereich“ derAction
. Jetzt sind unsere Unterschriften:Nun , wenn wir geben
runAction
einAction<S, T>
, sind wir sicher sein , dass , weil die „scope“ ParameterS
vollständig polymorph sind, ist es nicht den Körper entweichen kannrunAction
-so jeden Wert eines Typs , dass AnwendungenS
wieResource<S, int>
ebenfalls nicht entziehen können!(In Haskell ist dies als die
ST
Monade bekannt, worunAction
heißtrunST
,Resource
heißtSTRef
undnewResource
heißtnewSTRef
.)quelle
ST
Monade ist ein sehr interessantes Beispiel. Können Sie noch einige Beispiele nennen, wann ein höherrangiger Polymorphismus sinnvoll wäre?data Fetch d = forall a. Fetch (d a) (MVar a)
, das ein Paar aus einer Anforderung an eine Datenquelled
und einem Slot ist, in dem das Ergebnis gespeichert werden kann. Das Ergebnis und der Slot müssen übereinstimmende Typen haben, dieser Typ ist jedoch ausgeblendet, sodass Sie eine heterogene Liste von Anforderungen an dieselbe Datenquelle haben können. Jetzt können Sie höherrangigen Polymorphismus verwenden , um eine Funktion zu schreiben , die alle Anforderungen holt, da eine Funktion , die man holt:fetch :: (forall a. d a -> IO a) -> [Fetch d] -> IO ()
.Polymorphismus mit höherem Rang ist äußerst nützlich. In System F (der Kernsprache typisierter FP-Sprachen, mit der Sie vertraut sind) ist dies wesentlich, um "getippte Kirchenkodierungen" zuzulassen, wie dies in System F der Fall ist. Ohne diese ist System F völlig unbrauchbar.
In System F definieren wir Zahlen als
Zusatz hat den Typ
Dies ist ein Typ mit höherem Rang (der
forall c.
in diesen Pfeilen angezeigt wird).Dies kommt auch an anderen Stellen vor. Wenn Sie beispielsweise angeben möchten, dass eine Berechnung eine ordnungsgemäße Art der Weitergabe darstellt (google "codensity haskell"), können Sie dies als korrigieren
Selbst wenn in System F von einem unbewohnten Typ gesprochen wird, ist ein Polymorphismus mit höherem Rang erforderlich
Das lange und kurze Schreiben einer Funktion in einem reinen Typensystem (System F, CoC) erfordert einen höherrangigen Polymorphismus, wenn wir mit interessanten Daten umgehen wollen.
Insbesondere in System F müssen diese Codierungen "anregend" sein. Dies bedeutet, dass a
forall a.
über absolut alle Typen quantifiziert . Dies schließt genau den Typ ein, den wir definieren. Inforall a. a
dasa
könnte tatsächlich stehenforall a. a
wieder! In Sprachen wie ML ist dies nicht der Fall, sie werden als "prädikativ" bezeichnet, da eine Typvariable nur über den Satz von Typen ohne Quantifizierer (sogenannte Monotypen) quantifiziert. Unsere Definition vonplus
erforderlichen impredicativity auch , weil wir instanziiert diec
inl : Nat
seinNat
!Abschließend möchte ich einen letzten Grund erwähnen, aus dem Sie sowohl Impredikativität als auch höherrangigen Polymorphismus wünschen, selbst in einer Sprache mit willkürlich rekursiven Typen (im Gegensatz zu System F). In Haskell gibt es eine Monade für Effekte, die als "State Thread Monad" bezeichnet wird. Die Idee ist, dass die Status-Thread-Monade Sie Dinge mutieren lässt, aber es erfordert, dass Ihr Ergebnis nicht von etwas Mutierbarem abhängt. Dies bedeutet, dass ST-Berechnungen beobachtbar rein sind. Um diese Anforderung durchzusetzen, verwenden wir einen höherrangigen Polymorphismus
Indem
a
wir sicherstellen, dass dies außerhalb des Bereichs liegt, in dem wir es einführens
, wissen wir, dass esa
sich um einen wohlgeformten Typ handelt, der nicht auf etwas angewiesen ists
. Wir verwendens
, um alle veränderlichen Dinge in diesem bestimmten Status-Thread zu paramerisieren, damit wir wissen, dass diesa
unabhängig von veränderlichen Dingen ist und daher nichts dem Umfang dieserST
Berechnung entgeht ! Ein wunderbares Beispiel für die Verwendung von Typen, um schlecht geformte Programme auszuschließen.Übrigens, wenn Sie etwas über Typentheorie lernen möchten, würde ich vorschlagen, in ein oder zwei gute Bücher zu investieren. Es ist schwer, dieses Zeug in Einzelteilen zu lernen. Ich würde eines von Pierces oder Harpers Büchern über PL-Theorie im Allgemeinen (und einige Elemente der Typentheorie) vorschlagen. Das Buch "Fortgeschrittene Themen in Typen und Programmiersprachen" behandelt auch ein gutes Maß an Typentheorie. Schließlich ist "Programmieren in der Typentheorie von Martin Lof" eine sehr gute Darstellung der umrissenen intensionalen Typentheorie von Martin Lof.
quelle