Então, eu estou familiarizado com duas estratégias principais de ter polimorfismo de classificação mais alta em um idioma:
- Polimorfismo no estilo System-F, em que as funções são explicitamente digitadas e a instanciação ocorre explicitamente no tipo de aplicativo. Esses sistemas podem ser impredicativos.
- Polimorfismo baseado em subtipagem, em que um tipo polimórfico é um subtipo de todas as suas instanciações. Para ter uma subtipo decidível, o polimorfismo deve ser predicativo. Este documento fornece um exemplo desse sistema.
No entanto, algumas linguagens, como Haskell, têm polimorfismo impredicativo de classificação mais alta sem aplicativos explícitos.
Como isso é possível? Como a verificação de tipo "sabe" quando instanciar um tipo sem uma instanciação ou conversão explícita e sem uma noção de subtipagem?
Ou, tipechecking é mesmo decidível em tal sistema? É um caso em que linguagem como Haskell implementa algo indecidível que funciona para os casos de uso da maioria das pessoas.
EDITAR:
Para ser claro, estou interessado nos usos , não nas definições, dos valores digitados polimorficamente.
Por exemplo, suponha que tenhamos:
f : forall a . a -> a
g : (forall a . a -> a) -> Int
val = (g f, f True, f 'a')
Como podemos saber que precisamos instanciar f
quando ela é aplicada, mas não quando é apresentada como argumento?
Ou, para nos separar dos tipos de função:
f : forall a . a
g : (forall a . a) -> Int
val = (g f, f && True, f + 0)
Aqui, não podemos sequer distinguir o uso de f
aplicá-lo versus passá-lo: ele é instanciado quando passado como argumento para &&
e +
, mas não g
.
Como um sistema teórico pode distinguir esses dois casos sem uma regra mágica de "você pode converter qualquer tipo polimórfico em sua instância"? Ou com uma regra como essa, podemos saber quando aplicá-la, para manter a decisão?
g
espera um tipo e evita a instanciação de f
.
\f -> (f True, f 'a')
não vai tipo de verificação, mesmo se ele pode ser atribuído ao tipo(forall t. t->t) -> (Bool, Char)