Veo algunas discusiones interesantes aquí sobre la escritura estática frente a la dinámica. Generalmente prefiero la escritura estática, debido a la verificación de tipos de compilación, código mejor documentado, etc. Sin embargo, estoy de acuerdo en que desordenan el código si se hace de la manera en que lo hace Java, por ejemplo.
Así que estoy a punto de comenzar a construir un lenguaje de estilo funcional propio, y la inferencia de tipos es una de las cosas que quiero implementar. Entiendo que es un gran tema, y no estoy tratando de crear algo que no se haya hecho antes, solo una inferencia básica ...
¿Algún consejo sobre qué leer que me ayude con esto? Preferiblemente, algo más pragmático / práctico en lugar de textos de teoría de categorías / teoría de tipos más teóricos. Si hay un texto de discusión de implementación, con estructuras de datos / algoritmos, sería maravilloso.
Respuestas:
Encontré los siguientes recursos útiles para comprender la inferencia de tipos, en orden de dificultad creciente:
Sin embargo, dado que la mejor manera de aprender es hacerlo, sugiero encarecidamente implementar la inferencia de tipos para un lenguaje funcional de juguete trabajando a través de una tarea de un curso de lenguajes de programación.
Recomiendo estas dos tareas accesibles en ML, que ambos pueden completar en menos de un día:
Estas asignaciones son de un curso más avanzado:
Implementando MiniML
Tipos polimórficos, existenciales y recursivos (PDF)
Comprobación de tipo bidireccional (PDF)
Subtipado y objetos (PDF)
fuente
Es lamentable que mucha de la literatura sobre el tema sea muy densa. Yo también estaba en tus zapatos. Recibí mi primera introducción al tema de Lenguajes de programación: aplicaciones e interpretación.
http://www.plai.org/
Intentaré resumir la idea abstracta seguida de detalles que no encontré inmediatamente obvios. Primero, se puede pensar en la inferencia de tipos para generar y luego resolver restricciones. Para generar restricciones, recorre el árbol de sintaxis y genera una o más restricciones en cada nodo. Por ejemplo, si el nodo es un
+
operador, los operandos y los resultados deben ser todos números. Un nodo que aplica una función tiene el mismo tipo que el resultado de la función, y así sucesivamente.Para un idioma sin
let
, puede resolver ciegamente las restricciones anteriores mediante sustitución. Por ejemplo:aquí, podemos decir que la condición de la instrucción if debe ser booleana, y que el tipo de instrucción if es el mismo que el tipo de sus cláusulas
then
yelse
. Como sabemos1
y2
somos números, por sustitución, sabemos que elif
enunciado es un número.Donde las cosas se ponen feas, y lo que no pude entender por un tiempo, es lidiar con dejar:
Aquí, nos hemos vinculado
id
a una función que devuelve lo que haya pasado, también conocida como función de identidad. El problema es que el tipo de parámetro de la funciónx
es diferente en cada uso deid
. La segundaid
es una función de tipoa -> a
, dondea
puede haber cualquier cosa. El primero es de tipo(a -> a) -> (a -> a)
. Esto se conoce como polimorfismo let. La clave es resolver las restricciones en un orden particular: primero resuelva las restricciones para la definición deid
. Esto seráa -> a
. Luego,id
se pueden sustituir copias nuevas y separadas del tipo de en las restricciones para cada lugarid
, por ejemploa2 -> a2
ya3 -> a3
.Eso no se explicó fácilmente en los recursos en línea. Mencionarán el algoritmo W o M, pero no cómo funcionan en términos de resolución de restricciones, o por qué no se burla del polimorfismo let: cada uno de esos algoritmos impone un orden para resolver las restricciones.
Encontré este recurso extremadamente útil para vincular el algoritmo W, M y el concepto general de generación de restricciones y resolución de todos juntos. Es un poco denso, pero mejor que muchos:
http://www.cs.uu.nl/research/techreps/repo/CS-2002/2002-031.pdf
Muchos de los otros artículos también son buenos:
http://people.cs.uu.nl/bastiaan/papers.html
Espero que ayude a aclarar un mundo algo turbio.
fuente
Además de Hindley Milner para lenguajes funcionales, otro enfoque popular para la inferencia de tipos para lenguaje dinámico es
abstract interpretation
.La idea de la interpretación abstracta es escribir un intérprete especial para el lenguaje, en lugar de mantener un entorno de valores concretos (1, falso, cierre), funciona con valores abstractos, también conocidos como tipos (int, bool, etc.). Dado que está interpretando el programa en valores abstractos, por eso se llama interpretación abstracta.
Pysonar2 es una elegante implementación de interpretación abstracta para Python. Google lo utiliza para analizar proyectos de Python. Básicamente, se utiliza
visitor pattern
para enviar una llamada de evaluación al nodo AST relevante. La función de visitantetransform
acepta elcontext
en el que se evaluará el nodo actual y devuelve el tipo de nodo actual.fuente
Tipos y lenguajes de programación por Benjamin C. Pierce
fuente
Lambda the Ultimate, comenzando aquí .
fuente