2011-01-04 11 views
5

No estoy seguro de saber siquiera cómo formular esta pregunta. Al implementar un compilador, me gustaría permitir que el cliente especifique, digamos, pliegues en tuplas. He proporcionado una forma de curry y desencadenar una función, pero solo porque escribí un operador binario en Ocaml y lo doblé sobre el término y escribí las representaciones. El usuario no pudo escribir esta función.Implementar y representar operaciones polyadic

En el procesador de macros, el usuario puede escribir esta función porque las tuplas son listas.

Para las funciones curried, el usuario puede escribir fácilmente transformadores, porque el término es binario tanto en el idioma de destino como en la representación Ocaml del término y el tipado.

Pero no pueden hacer esto para las tuplas. Aquí hay otro ejemplo: el usuario define fácilmente el operador de composición funcional en serie. Pero el usuario no puede definir composición paralela: la versión binaria:

f1: D1 -> C1, f2: D2-> C2 --> f1 * f2: D1 * D2 -> C1 * C2 

se puede escribir fácilmente, pero no puede ser extendido a 3 términos: aquí un pliegue calcularía

f1 * (f2 * f3) 

en lugar de

f1 * f2 * f3 

[isomorfo pero no igual]

La generalización de esta pregunta es "Cómo ¿Implemento un lenguaje de programación polyadic "que es demasiado pedir aquí. Lo que traté de hacer fue proporcionar un transformador incorporado:

curry: T1 * T2 * T3 ... -> T1 -> T2 -> ... uncurry: T1 -> T2 -> .. T1 * T2 T3 *

es así, el usuario sólo podía hacer pliegues con un operador binario:

uncurry (fold user_op (uncurry term)) 

pero esto no es ni lo suficientemente general ni funciona tan bien .. :)

supongo una pregunta equivalente para Haskell sería: dado que Haskell no tiene productos n-arios, se simulan los constructores de tuplas n-arios en la biblioteca con n funciones, donde cada uno debe escribirse a mano. Esto claramente apesta. ¿Cómo sería esto solucionado?

[quiero decir, es trivial para escribir una secuencia de comandos de Python para generar esas funciones n hasta un límite n, ¿por qué es tan difícil de hacer esto de una manera bien escrito dentro del lenguaje?]

Respuesta

2

hay dos componentes que colaboran para provocar este problema:

  • tuplas no son auto-aplanado - los paréntesis en las expresiones de tipo hacen más de grupo, crean tipos distintos que están unidas por otras tuplas. Esto lleva a su observación de que a * (b * c) es isomorfo pero no es equivalente a a * b * c.
  • El sistema de tipo no proporciona un medio para expresar álgebra en tipos de tupla. Con esto quiero decir que el sistema de tipo no tiene un operador contras o cualquier equivalente para tuplas; no hay forma de expresar que un tipo tiene más o menos elementos agrupados que otro tipo.

El resultado es que no hay forma de expresar el tipo de una función que opera en tuplas de longitud arbitraria.

Por lo tanto, el breve resumen es que el sistema de tipo OCaml carece de mecanismos para expresar el tipo de función que está intentando escribir, y por lo tanto no puede escribir la función (apartar juegos desagradables con Obj; podría escribir la función , pero no pudo expresar su tipo para usarlo de una manera segura para el tipo).

+2

Sí, pero esa no es mi pregunta: no estoy preguntando sobre qué tipo de sistema hace Ocaml, estoy preguntando cómo implementar esto en otro idioma (mi lenguaje Félix, de hecho, el compilador está escrito en Ocaml) – Yttrill

0

Existen básicamente dos opciones.

Puede hacer que su lenguaje sea sin tipo o débilmente tipeado. En C, por ejemplo, las tuplas (de enteros, por ejemplo) se pueden representar como int*. Algo tendría que hacer un seguimiento de las longitudes de las tuplas, pero el sistema de tipos no lo hará. Supongo que no quieres ir por ese camino.

Para un lenguaje seguro, necesita un sistema de tipo muy expresivo. A saber, necesitas tipos que dependen de los valores. Los miembros de los cuales son funciones que devuelven tipos. Por ejemplo, el constructor del tipo de tupla (que no debe confundirse con el constructor de tuplas) podría tener el tipo tuple : int -> Type -> Type. Una operación que extiende una tupla podría tener el tipo forall n:int. forall T:Type. tuple n T -> T -> tuple (n+1) T. Estos tipos de sistemas tienen un costo: por lo general, la inferencia de tipo no es recursiva y la verificación de tipo solo es decidible si está dispuesto a anotar todo tipo de subexpresiones con su tipo (las anotaciones en las partes anteriores forall son solo una pista de lo que haría implicar.). Esta opción parece ser exagerada si todo lo que quiere lograr es poliadicidad.

Descargo de responsabilidad: Mi conocimiento sobre la teoría de tipos está un poco anticuado.

+0

Tienes razón, no quiero teclear débilmente. Sin embargo, me desagrada la inferencia de tipo, por lo que no me importa si la mecanografía debe ser explícita. Mecanografía totalmente dependiente sería excesivo, creo. Incluso en el lenguaje de ATS Hongwei Xi), pronto se ve que cuando uno trata de extenderse mucho más allá de las fórmulas simples de números enteros, la verificación de la prueba no es práctica, sino intratable. – Yttrill

+0

BTW: lo molesto es que puedes hacer este tipo de cosas bastante fácilmente sin verificación de tipos: en C++ con plantillas y en Scheme. Mi sistema en Felix podría hacer tuples contras, simplemente no funciona con matrices (que son idénticas a las tuplas con un tipo de elemento común). Pero uno necesita mucho más que simples contras y desconexiones. Con GADTs puedo hacer más. Pero esta colección de características geniales son solo hacks. No es general. Sin embargo, puedo hacer cualquier cosa simplemente usando Python para "imprimir" el código que quiero. – Yttrill

+0

BTW: creo que hay una alternativa al tipado dependiente (tipos que dependen de los valores), que es meta-typing (kinding). Por ejemplo, una matriz de longitud 5 en Felix ya es de tipo T^5, donde 5 es una suma de 5 unidades 1 + 1 + 1 + 1 + 1, donde 1 es el tipo "unidad" de valor(). Entonces, si hubiera un tipo "Unitsum" entonces tuple: int -> Tipo -> Tipo sería reescrito tuple: Unitsum -> Type -> type, que ya no requiere mecanografía dependiente, sino un sistema kinding. – Yttrill

Cuestiones relacionadas