Vejo algumas discussões interessantes aqui sobre tipagem estática x dinâmica. Eu geralmente prefiro a tipagem estática, devido à verificação de tipo de compilação, código melhor documentado, etc. No entanto, eu concordo que eles bagunçam o código se feitos da maneira que o Java faz, por exemplo.
Portanto, estou prestes a começar a construir minha própria linguagem de estilo funcional, e a inferência de tipos é uma das coisas que desejo implementar. Eu entendo que é um grande assunto, e não estou tentando criar algo que não tenha sido feito antes, apenas inferência básica ...
Alguma sugestão sobre o que ler que me ajudará com isso? De preferência, algo mais pragmático / prático em oposição a textos mais teóricos da teoria das categorias / teoria dos tipos. Se houver um texto de discussão de implementação por aí, com estruturas de dados / algoritmos, isso seria ótimo.
Respostas:
Achei os seguintes recursos úteis para entender a inferência de tipo, em ordem crescente de dificuldade:
No entanto, como a melhor maneira de aprender é fazendo, sugiro fortemente a implementação de inferência de tipo para uma linguagem funcional de brinquedo, trabalhando em uma tarefa de casa de um curso de linguagens de programação.
Eu recomendo estes dois trabalhos de casa acessíveis em ML, que você pode concluir em menos de um dia:
Essas tarefas são de um curso mais avançado:
Implementando MiniML
Tipos polimórficos, existenciais e recursivos (PDF)
Verificação de tipo bidirecional (PDF)
Subtipagem e objetos (PDF)
fonte
É uma pena que grande parte da literatura sobre o assunto seja muito densa. Eu também estava no seu lugar. Tive minha primeira introdução ao assunto em Linguagens de Programação: Aplicações e Interpretação
http://www.plai.org/
Tentarei resumir a ideia abstrata seguida de detalhes que não achei imediatamente óbvios. Em primeiro lugar, a inferência de tipo pode ser pensada para gerar e, em seguida, resolver restrições. Para gerar restrições, você percorre novamente a árvore de sintaxe e gera uma ou mais restrições em cada nó. Por exemplo, se o nó for um
+
operador, os operandos e os resultados devem ser todos números. Um nó que aplica uma função tem o mesmo tipo que o resultado da função e assim por diante.Para uma linguagem sem
let
, você pode resolver cegamente as restrições acima por substituição. Por exemplo:aqui, podemos dizer que a condição da instrução if deve ser booleana e que o tipo da instrução if é o mesmo que o tipo de suas cláusulas
then
eelse
. Visto que sabemos1
e2
somos números, por substituição, sabemos que aif
afirmação é um número.Onde as coisas ficam feias, e o que eu não conseguia entender por um tempo, é lidar com isso:
Aqui, associamos
id
a uma função que retorna tudo o que você passou, também conhecido como função de identidade. O problema é que o tipo de parâmetro da funçãox
é diferente em cada uso deid
. A segundaid
é uma função do tipoa -> a
, ondea
pode ser qualquer coisa. O primeiro é do tipo(a -> a) -> (a -> a)
. Isso é conhecido como polimorfismo let. A chave é resolver as restrições em uma ordem particular: primeiro resolva as restrições para a definição deid
. Isso vai sera -> a
. Em seguida, cópias novas e separadas do tipo deid
podem ser substituídas nas restrições de cada localid
, por exemploa2 -> a2
ea3 -> a3
.Isso não foi explicado prontamente nos recursos online. Eles mencionarão o algoritmo W ou M, mas não como eles funcionam em termos de resolução de restrições, ou por que ele não vomita no polimorfismo let: cada um desses algoritmos impõe uma ordem na resolução das restrições.
Achei este recurso extremamente útil para amarrar o Algoritmo W, M e o conceito geral de geração de restrição e resolução de todos juntos. É um pouco denso, mas melhor do que muitos:
http://www.cs.uu.nl/research/techreps/repo/CS-2002/2002-031.pdf
Muitos dos outros papéis também são bons:
http://people.cs.uu.nl/bastiaan/papers.html
Espero que ajude a esclarecer um mundo um tanto obscuro.
fonte
Além de Hindley Milner para linguagens funcionais, outra abordagem popular para inferência de tipos para linguagem dinâmica é
abstract interpretation
.A ideia da interpretação abstrata é escrever um intérprete especial para a linguagem, ao invés de manter um ambiente de valores concretos (1, false, closure), funciona em valores abstratos, também conhecidos como tipos (int, bool, etc). Como ele interpreta o programa em valores abstratos, é por isso que é chamado de interpretação abstrata.
Pysonar2 é uma implementação elegante de interpretação abstrata para Python. Ele é usado pelo Google para analisar projetos Python. Basicamente, ele usa
visitor pattern
para despachar a chamada de avaliação para o nó AST relevante. A função de visitantetransform
aceita ocontext
no qual o nó atual será avaliado e retorna o tipo de nó atual.fonte
Tipos e linguagens de programação de Benjamin C. Pierce
fonte
Lambda the Ultimate, começando aqui .
fonte