Estou trabalhando em um pequeno compilador de cálculo lambda que possui um sistema de inferência do tipo Hindley-Milner em funcionamento e agora também oferece suporte a vamos recursivos (não no código vinculado), que eu entendo que deve ser suficiente para torná-lo completo .
O problema agora é que não tenho idéia de como fazê-lo, ou se ele já os suporta e só preciso encontrar uma maneira de codificá-los. Eu gostaria de poder defini-los sem precisar adicionar novas regras ao sistema de tipos.
A maneira mais fácil de pensar em uma lista x
é como algo que é null
(ou a lista vazia) ou um par que contém uma x
e uma lista de x
. Mas, para fazer isso, preciso ser capaz de definir pares e ou 's, que acredito serem os tipos de produto e soma.
Parece que eu posso definir pares desta maneira:
pair = λabf.fab
first = λp.p(λab.a)
second = λp.p(λab.b)
Uma vez pair
que teria o tipo a -> (b -> ((a -> (b -> x)) -> x))
, depois de passar, digamos, an int
e a string
, produziria algo com o tipo (int -> (string -> x)) -> x
, que seria a representação de um par de int
e string
. O que me incomoda aqui é que, se isso representa um par, por que isso não é logicamente equivalente ou implica a proposição int and string
? No entanto, é equivalente a (((int and string) -> x) -> x)
, como se eu pudesse ter apenas tipos de produtos como parâmetros para funções. Esta respostaparece resolver esse problema, mas não tenho idéia do significado dos símbolos que ele usa. Além disso, se isso realmente não codifica um tipo de produto, há algo que eu possa fazer com os tipos de produtos que eu não poderia fazer com minha definição de pares acima (considerando que eu também posso definir n-tuplas da mesma maneira)? Caso contrário, isso não contradiz o fato de que você não pode expressar a conjunção (AFAIK) usando apenas implicação?
Além disso, e o tipo de soma? De alguma forma, posso codificá-lo usando apenas o tipo de função? Em caso afirmativo, isso seria suficiente para definir listas? Ou então, existe outra maneira de definir listas sem precisar estender meu sistema de tipos? E, se não, que mudanças eu precisaria fazer para manter o mais simples possível?
Lembre-se de que sou um programador de computadores, mas não um cientista da computação, nem um matemático e muito ruim em ler notações matemáticas.
Edit: Não tenho certeza de qual é o nome técnico do que implementei até agora, mas tudo o que tenho é basicamente o código que vinculei acima, que é um algoritmo de geração de restrição que usa as regras para aplicativos, abstrações e variáveis obtidas do algoritmo Hinley-Milner e, em seguida, um algoritmo de unificação que obtém o tipo principal. Por exemplo, a expressão \a.a
produzirá o tipo a -> a
e a expressão \a.(a a)
lançará um erro de verificação de ocorrência. Além disso, não existe exatamente uma let
regra, mas uma função que parece ter o mesmo efeito que permite definir funções globais recursivas como este pseudo-código:
GetTypeOfGlobalFunction(term, globalScope, nameOfFunction)
{
// Here 'globalScope' contains a list of name-value pair where every value is of class 'ClosedType',
// meaning their type will be cloned before unified in the unification algorithm so that they can be used polymorphically
tempType = new TypeVariable() // Assign a dummy type to `tempType`, say, type 'x'.
// The next line creates an scope with everything in 'globalScope' plus the 'nameOfFunction = tempType' name-value pair
tempScope = new Scope(globalScope, nameOfFunction, tempType)
type = TypeOfTerm(term, tempScope) // Calculate the type of the term
Unify(tempType, type)
return type
// After returning, the code outside will create a 'ClosedType' using the returned type and add it to the global scope.
}
O código basicamente obtém o tipo do termo como de costume, mas antes da unificação, ele adiciona o nome da função que está sendo definida com um tipo fictício no escopo do tipo, para que possa ser usado recursivamente dentro de si.
Edição 2: Acabei de perceber que também precisaria de tipos recursivos, que não tenho, para definir uma lista como eu quero.
let func = \x -> (func x)
), você obtém o que tenho.