Estoy trabajando en un pequeño compilador de cálculo lambda que tiene un sistema de inferencia de tipo Hindley-Milner y ahora también admite recursivos Let's (no en el código vinculado), que entiendo que debería ser suficiente para completar Turing .
El problema ahora es que no tengo idea de cómo hacer que sea compatible con listas, o si ya las admite y solo necesito encontrar una manera de codificarlas. Me gustaría poder definirlos sin tener que agregar nuevas reglas al sistema de tipos.
La forma más fácil en que puedo pensar en una lista x
es como algo que es null
(o la lista vacía), o un par que contiene tanto una x
como una lista de x
. Pero para hacer esto necesito poder definir pares y o, que creo que son el producto y los tipos de suma.
Parece que puedo definir pares de esta manera:
pair = λabf.fab
first = λp.p(λab.a)
second = λp.p(λab.b)
Dado pair
que tendría el tipo a -> (b -> ((a -> (b -> x)) -> x))
, después de pasar, digamos, an int
y a string
, produciría algo con tipo (int -> (string -> x)) -> x
, que sería la representación de un par de int
y string
. Lo que me molesta aquí es que si eso representa un par, ¿por qué eso no es lógicamente equivalente a, ni implica la proposición int and string
? Sin embargo, es equivalente a (((int and string) -> x) -> x)
, como si solo pudiera tener tipos de productos como parámetros para las funciones. Esta respuestaparece abordar este problema, pero no tengo idea de qué significan los símbolos que usa. Además, si esto realmente no codifica un tipo de producto, ¿hay algo que pueda hacer con los tipos de productos que no podría hacer con mi definición de pares anterior (considerando que también puedo definir n-tuplas de la misma manera)? Si no, ¿no contradiría esto el hecho de que no puede expresar la conjunción (AFAIK) usando solo implicación?
Además, ¿qué tal el tipo de suma? ¿Puedo codificarlo de alguna manera usando solo el tipo de función? Si es así, ¿sería esto suficiente para definir listas? O bien, ¿hay alguna otra forma de definir listas sin tener que extender mi sistema de tipos? Y si no, ¿qué cambios necesitaría hacer si quiero que sea lo más simple posible?
Tenga en cuenta que soy un programador de computadoras pero no un científico de la computación ni un matemático y soy bastante malo leyendo la notación matemática.
Editar: no estoy seguro de cuál es el nombre técnico de lo que he implementado hasta ahora, pero todo lo que tengo es básicamente el código que he vinculado anteriormente, que es un algoritmo de generación de restricciones que usa las reglas para aplicaciones, abstracciones y variables tomadas del algoritmo Hinley-Milner y luego un algoritmo de unificación que obtiene el tipo principal. Por ejemplo, la expresión \a.a
arrojará el tipo a -> a
y \a.(a a)
arrojará un error de verificación de ocurrencia. Además de esto, no existe exactamente una let
regla, sino una función que parece tener el mismo efecto que le permite definir funciones globales recursivas como este pseudocó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.
}
Básicamente, el código obtiene el tipo del término como de costumbre, pero antes de unificar, agrega el nombre de la función que se define con un tipo ficticio en el ámbito de tipo para que pueda usarse desde dentro de sí mismo de forma recursiva.
Edición 2: Acabo de darme cuenta de que también necesitaría tipos recursivos, que no tengo, para definir una lista como quiero.
let func = \x -> (func x)
) obtendrá lo que tengo.