Полиморфизм высшего ранга чрезвычайно полезен. В System F (основной язык типизированных языков FP, с которым вы знакомы), это важно для принятия «типизированных кодировок Церкви», что фактически делает System F программированием. Без них система F совершенно бесполезна.
В системе F мы определяем числа как
Nat = forall c. (c -> c) -> c -> c
Дополнение имеет тип
plus : Nat -> Nat -> Nat
plus l r = Λ t. λ (s : t -> t). λ (z : t). l s (r s z)
который является типом более высокого ранга ( forall c.
появляется внутри этих стрелок).
Это встречается и в других местах. Например, если вы хотите указать, что вычисление является правильным стилем передачи продолжения (google "codensity haskell"), то вы должны исправить это как
type CPSed A = forall c. (A -> c) -> c
Даже разговор о необитаемом типе в System F требует более высокого ранга полиморфизма
type Void = forall a. a
Короче говоря, написание функции в системе чистого типа (System F, CoC) требует более высокого ранга полиморфизма, если мы хотим иметь дело с любыми интересными данными.
В частности, в Системе F эти кодировки должны быть «непредсказуемыми». Это означает, что forall a.
количественно определяет абсолютно все типы . Это включает в себя тот самый тип, который мы определяем. В forall a. a
этом на a
самом деле может стоять forall a. a
снова! В таких языках, как ML, это не так, их называют «предикативными», поскольку переменная типа количественно определяет только набор типов без квантификаторов (называемых монотипами). Наше определение plus
требуемого impredicativity, а потому , что мы создания экземпляра c
в l : Nat
быть Nat
!
Наконец, я хотел бы упомянуть одну последнюю причину, по которой вам нужны как непредсказуемость, так и полиморфизм более высокого ранга даже в языке с произвольно рекурсивными типами (в отличие от System F). В Haskell есть монада для эффектов, называемая «монадой потока состояний». Идея состоит в том, что монада потока состояний позволяет вам мутировать вещи, но требует экранирования, чтобы ваш результат не зависел от чего-либо изменяемого. Это означает, что вычисления ST являются чисто наблюдаемыми. Для выполнения этого требования мы используем полиморфизм более высокого ранга
runST :: forall a. (forall s. ST s a) -> a
Здесь, гарантируя, что a
это ограничено пределами области, в которой мы представляем s
, мы знаем, что a
означает хорошо сформированный тип, на который не полагаются s
. Мы используем s
для параметризации всех изменяемых вещей в этом конкретном потоке состояний, чтобы мы знали, что a
это не зависит от изменяемых вещей и, таким образом, ничто не выходит за рамки этих ST
вычислений! Прекрасный пример использования типов для исключения некорректных программ.
Кстати, если вы заинтересованы в изучении теории типов, я бы предложил инвестировать в хорошую книгу или две. Трудно выучить этот материал по частям. Я бы предложил одну из книг Пирса или Харпера по теории PL в целом (и некоторые элементы теории типов). Книга "Расширенные темы по типам и языкам программирования" также охватывает большое количество теории типов. Наконец, «Программирование в теории типов Мартина Лофа» является очень хорошим изложением теории интенсиональных типов, изложенной Мартином Лофом.
let sdff = (g : (f : <T> (e : T) => void) => void) => {}