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?
\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)
g
espera um tipo e evita a instanciação def
.Respostas:
A introdução do artigo de Dunfield e Krishnaswami refere-se à inferência prática de tipo para tipos de classificação arbitrária
Na abordagem System F-ish, também há uma relação de "subtipagem". Consulte a seção 3.3 Subsunção.
Eu também enfatizaria que Haskell não tem tipos impredicativos (ou inferência para eles). Consulte: https://mail.haskell.org/pipermail/ghc-devs/2016-September/012940.html para obter indicadores.
Ou seja
id id
, sempre será elaborado comonão
No entanto, você pode escrever o último explicitamente, se ativar
ImpredicativeTypes
.fonte
Para verificar a aplicação de uma função como
g : (forall a. a -> a) -> Int
af
, precisamos verificar issof : forall a. a -> a
.Em vez de combinar quantificadores (que seriam bastante frágeis), introduzimos uma variável nova e rígida (ou seja, não unificável), digamos
a1
, e precisamos verificar issof : a1 -> a1
, e agora podemos continuar como de costume, instanciandof
ema1
(módulo adicional verificações para garantir quea1
não escapa ao seu escopo).O algoritmo real é detalhado no artigo phadej vinculado.
O problema geral da inferência de tipo na presença de polimorfismo de classificação mais alta permanece indecidível. No entanto, com anotações de tipo completo, torna-se um problema de verificação de tipo decidível (principalmente?) . O algoritmo do GHC deve, portanto, ser incompleto, mas tenta cobrir o máximo de terreno possível no meio dessas duas situações, com a ajuda de algumas anotações de tipo esparso.
fonte