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, fmuss in der Lage sein, mir Inteinen 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 Actionsie 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 Sden Resourceund 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 runActionein Action<S, T>, sind wir sicher sein , dass , weil die „scope“ Parameter Svollständig polymorph sind, ist es nicht den Körper entweichen kann runAction-so jeden Wert eines Typs , dass Anwendungen Swie Resource<S, int>ebenfalls nicht entziehen können!
(In Haskell ist dies als die STMonade bekannt, wo runActionheißt runST, Resourceheißt STRefund newResourceheißt newSTRef.)
let sdff = (g : (f : <T> (e : T) => void) => void) => {}