Estoy trabajando en un compilador para un lenguaje concatenante y me gustaría agregar soporte de inferencia de tipos. Entiendo Hindley-Milner, pero he estado aprendiendo la teoría de tipos a medida que avanzo, así que no estoy seguro de cómo adaptarla. ¿El siguiente sistema es sólido y decididamente infeccioso?
Un término es un literal, una composición de términos, una cita de un término o un primitivo.
Todos los términos denotan funciones. Para dos funciones y , , es decir, la yuxtaposición denota la composición inversa. Los literales denotan funciones niládicas.
Los términos que no sean composición tienen reglas básicas de tipo:
Las reglas de aplicación son notablemente ausentes, ya que los lenguajes concatenantes carecen de ellas.
Un tipo es un literal, una variable de tipo o una función de pilas a pilas, donde una pila se define como una tupla anidada a la derecha. Todas las funciones son implícitamente polimórficas con respecto al "resto de la pila".
Esto es lo primero que parece sospechoso, pero no sé exactamente qué tiene de malo.
Para ayudar a la legibilidad y abajo corte en paréntesis, voy a suponer que en esquemas tipo. También usaré una letra mayúscula para una variable que denota una pila, en lugar de un solo valor.
Hay seis primitivas. Los primeros cinco son bastante inocuos. dup
toma el valor más alto y produce dos copias del mismo. swap
cambia el orden de los dos valores superiores. pop
descarta el valor superior. quote
toma un valor y produce una cita (función) que lo devuelve. apply
aplica una cita a la pila.
El último combinador compose
debería tomar dos citas y devolver el tipo de su concatenación, es decir, . En el lenguaje concatenativo estáticamente tipadoCat, el tipo dees muy sencillo.compose
Sin embargo, este tipo es demasiado restrictivo: requiere que la producción de la primera función coincida exactamente con el consumo de la segunda. En realidad, debe asumir distintos tipos y luego unificarlos. ¿Pero cómo escribirías ese tipo?
Si dejas denotar una diferencia de dos tipos, entonces creo que puedes escribir el tipo correctamente.compose
Esto es todavía relativamente sencillo: compose
toma una función y uno f 2 : D → E . Su resultado consume B por encima del consumo de f 2 no producido por f 1 , y produce D por encima de la producción de f 1 no consumido por f 2 . Esto da la regla para la composición ordinaria.
Sin embargo, no sé si este hipotético realidad corresponde a algo, y lo he estado persiguiendo en círculos durante el tiempo suficiente como para pensar que tomé un giro equivocado. ¿Podría ser una simple diferencia de tuplas?
¿Hay algo horriblemente roto sobre esto que no estoy viendo, o estoy en algo como el camino correcto? (Probablemente he cuantificado algunas de estas cosas erróneamente y también agradecería soluciones en esa área).
compose
twice
dup compose apply
[1 +] twice
[pop] twice
compose
Respuestas:
Las letras griegas se usan para las variables del resto de la pila solo por claridad.
La verificación de tipos de rango 2 es indecidible en general, creo, aunque se ha realizado un trabajo que da buenos resultados en la práctica (para Haskell):
La regla de tipo para la composición es simplemente:
Para que el sistema de tipos funcione en general, necesita la siguiente regla de especialización:
fuente
dup +
should have type+
has typedup +
, as that does not use compose, as you defined it above.[dup] [+] compose
. But I read