funciones de este tipo se encuentran a menudo en los combinadores de punto fijo. p.ej. una forma del Y combinator se escribe λf.(λx.f (x x)) (λx.f (x x))
. Los combinadores de punto fijo se utilizan para implementar la recursión general en cálculo lambda no tipeado sin construcciones recursivas adicionales, y esto es parte de lo que hace que el cálculo lambda no tipado sea completo.
Cuando las personas desarrollaron simply-typed lambda calculus, que es un ingenuo sistema de tipo estático encima del cálculo lambda, descubrieron que ya no era posible escribir tales funciones. De hecho, no es posible realizar una recursión general en el cálculo lambda de tipo simple; y por lo tanto, el cálculo lambda de tipo simple ya no es Turing-completo. (Un efecto secundario interesante es que los programas en escrito con sencillez cálculo lambda siempre terminar.)
lenguajes de programación real de tipo estático como necesidad ml estándar incorporados mecanismos recursivos para superar el problema, tales como las funciones recursivas con nombre (se definió con val rec
o fun
) y se denominaron tipos de datos recursivos.
Todavía es posible usar tipos de datos recursivos para simular algo como lo que quiere, pero no es tan bonito.
Básicamente, quiere definir un tipo como 'a foo = 'a foo -> 'a
; sin embargo, esto no está permitido. En su lugar, lo envuelve en un tipo de datos: datatype 'a foo = Wrap of ('a foo -> 'a);
datatype 'a foo = Wrap of ('a foo -> 'a);
fun unwrap (Wrap x) = x;
Básicamente, Wrap
y unwrap
se utilizan para transformar entre 'a foo
y 'a foo -> 'a
, y viceversa.
Cuando necesite llamar a una función sobre sí mismo, en lugar de x x
, debe escribir explícitamente (unwrap x) x
(o unwrap x x
); es decir, unwrap
lo convierte en una función que luego puede aplicar al valor original.
P.S. Otro lenguaje ML, OCaml, tiene una opción para habilitar tipos recursivos (normalmente desactivado); si ejecuta el intérprete o compilador con el indicador -rectypes
, entonces es posible escribir cosas como fun x -> x x
. Básicamente, entre bastidores, el verificador de tipos determina los lugares donde debe "ajustar" y "desenvolver" el tipo recursivo, y luego se los inserta por usted. No conozco ninguna implementación de ML estándar que tenga una funcionalidad similar de tipos recursivos.
Si alguien está interesado, encontré que esto se llama [Combinador U (vea la parte inferior de la página)] (http://www.ucombinator.org/), pero no pude encontrar mucho más al respecto. –
No sabía que se llamaba el combinador de U, pero como dice esa página, se usa para construir el programa (aparentemente más corto) no terminante del cálculo lambda sin tipo que puse en mi respuesta. –