Im Allgemeinen verwenden Sie einen höherrangigen Polymorphismus, wenn der Angerufene den Wert eines Typparameters anstelle des Aufrufers auswählen soll . Beispielsweise:
f :: (forall a. Show a => a -> Int) -> (Int, Int)
f g = (g "one", g 2)
Jede Funktion g
, die ich an diese übergebe, f
muss in der Lage sein, mir Int
einen Wert von einem Typ zu geben, von dem das einzige, was g
über diesen Typ weiß, ist, dass er eine Instanz von hat Show
. Das sind also koschere:
f (length . show)
f (const 42)
Das sind aber nicht:
f length
f succ
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 erzeugen T
, z. B. eine Zukunft oder einen Rückruf.
T runAction<T>(Action<T>)
runAction :: forall a. Action a -> a
Angenommen, wir haben auch eine Action
, die Resource<T>
Objekte zuordnen kann:
Action<Resource<T>> newResource<T>(T)
newResource :: forall a. a -> Action (Resource a)
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
den Resource
und Action
-Typen einen Parameter hinzufügen , der völlig abstrakt ist - er repräsentiert den „Geltungsbereich“ der Action
. Jetzt sind unsere Unterschriften:
T run<T>(<S> Action<S, T>)
Action<S, Resource<S, T>> newResource<T>(T)
runAction :: forall a. (forall s. Action s a) -> a
newResource :: forall s a. a -> Action s (Resource s a)
Nun , wenn wir geben runAction
ein Action<S, T>
, sind wir sicher sein , dass , weil die „scope“ Parameter S
vollständig polymorph sind, ist es nicht den Körper entweichen kann runAction
-so jeden Wert eines Typs , dass Anwendungen S
wie Resource<S, int>
ebenfalls nicht entziehen können!
(In Haskell ist dies als die ST
Monade bekannt, wo runAction
heißt runST
, Resource
heißt STRef
und newResource
heißt newSTRef
.)
let sdff = (g : (f : <T> (e : T) => void) => void) => {}