Polimorfismo de classificação mais alta é extremamente útil. No Sistema F (o idioma principal das linguagens FP digitadas com as quais você está familiarizado), isso é essencial para admitir "codificações da Igreja digitadas", que é realmente como o Sistema F faz a programação. Sem eles, o sistema F é completamente inútil.
No Sistema F, definimos números como
Nat = forall c. (c -> c) -> c -> c
A adição tem o tipo
plus : Nat -> Nat -> Nat
plus l r = Λ t. λ (s : t -> t). λ (z : t). l s (r s z)
que é um tipo de classificação mais alta ( forall c.
aparece dentro dessas setas).
Isso aparece em outros lugares também. Por exemplo, se você deseja indicar que um cálculo é um estilo de passagem de continuação adequado (google "codensity haskell"), então você faria isso como
type CPSed A = forall c. (A -> c) -> c
Mesmo falando sobre um tipo desabitado no Sistema F requer polimorfismo de classificação mais alta
type Void = forall a. a
O longo e curto disso, escrever uma função em um sistema de tipo puro (Sistema F, CoC) requer polimorfismo de classificação mais alta se quisermos lidar com dados interessantes.
No sistema F, em particular, essas codificações precisam ser "impredicativas". Isso significa que um forall a.
quantifica absolutamente todos os tipos . Isso inclui criticamente o tipo que estamos definindo. No forall a. a
que a
poderia realmente estar para forall a. a
novamente! Em linguagens como ML, esse não é o caso, eles são considerados "predicativos", uma vez que uma variável de tipo quantifica apenas o conjunto de tipos sem quantificadores (chamados monotipos). Nossa definição de plus
impredicatividade requerida também porque instanciamos o c
in l : Nat
to be Nat
!
Finalmente, gostaria de mencionar uma última razão pela qual você gostaria tanto de impredicatividade quanto de polimorfismo de classificação mais alta, mesmo em um idioma com tipos arbitrariamente recursivos (ao contrário do Sistema F). Em Haskell, há uma mônada para efeitos chamada "mônada de thread de estado". A idéia é que a mônada de encadeamento de estado permita que você mude as coisas, mas exija que ela escape para que seu resultado não dependa de nada mutável. Isso significa que os cálculos de ST são notavelmente puros. Para impor esse requisito, usamos polimorfismo de classificação mais alta
runST :: forall a. (forall s. ST s a) -> a
Aqui, garantindo que isso a
esteja fora do escopo em que apresentamos s
, sabemos que isso a
significa um tipo bem formado, no qual não se baseia s
. Usamos s
para parameritizar todas as coisas mutáveis nesse segmento de estado específico, para que saibamos que a
é independente das coisas mutáveis e, portanto, que nada escapa ao escopo desse ST
cálculo! Um exemplo maravilhoso de uso de tipos para descartar programas mal formados.
A propósito, se você estiver interessado em aprender sobre a teoria dos tipos, sugiro investir em um bom livro ou dois. É difícil aprender essas coisas em pedaços. Eu sugeriria um dos livros de Pierce ou Harper sobre a teoria da PL em geral (e alguns elementos da teoria dos tipos). O livro "Tópicos avançados em tipos e linguagens de programação" também abrange uma boa quantidade de teoria de tipos. Finalmente, "Programar na teoria dos tipos de Martin Lof" é uma exposição muito boa da teoria dos tipos intensional que Martin Lof delineou.
let sdff = (g : (f : <T> (e : T) => void) => void) => {}