Bueno, algo conocido como parametricidad nos dice que si consideramos el subconjunto puro de ML (es decir, sin recursión infinita refy todas esas cosas raras), no hay forma de definir una función con este tipo que no sea la que devuelve el vacío lista.
Todo esto comenzó con el artículo de Wadler "¡ Teoremas gratis! ". Este artículo, básicamente, nos dice dos cosas:
- Si consideramos lenguajes de programación que satisfacen ciertas condiciones, podemos deducir algunos teoremas geniales simplemente mirando la firma de tipo de una función polimórfica (esto se llama Teorema de Parametricidad).
- ML (sin recursión infinita
refy todas esas cosas raras) satisface esas condiciones.
Desde el teorema Parametricity sabemos que si tenemos una función f : 'a list -> 'b list, a continuación, para todos 'a, 'b, 'c, 'dy para todas las funciones g : 'a -> 'c, h : 'b -> 'dtenemos:
map h ∘ f = f ∘ map g
(Nota, fa la izquierda tiene tipo 'a list -> 'b listy fa la derecha es 'c list -> 'd list).
Somos libres de elegir lo gque queramos, así que deja 'a = 'cy g = id. Ahora desde map id = id(fácil de probar por inducción en la definición de map), tenemos:
map h ∘ f = f
Ahora deja 'b = 'd = booly h = not. Asumamos que para algunos zs : bool listsucede eso f zs ≠ [] : bool list. Está claro que map not ∘ f = fno se sostiene, porque
(map not ∘ f) zs ≠ f zs
Si el primer elemento de la lista de la derecha es true, entonces, a la izquierda, el primer elemento es falsey viceversa.
Esto significa que nuestra suposición es incorrecta y f zs = []. ¿Terminamos? No.
Asumimos que 'bes bool. Hemos demostrado que cuando fse invoca con type f : 'a list -> bool listpara any 'a, fsiempre debe devolver la lista vacía. ¿Puede ser que cuando llamamos fya f : 'a list -> unit listque devuelve algo diferente? Nuestra intuición nos dice que esto no tiene sentido: simplemente no podemos escribir en ML pura una función que siempre devuelve la lista vacía cuando queremos que nos dé una lista de booleanos y de lo contrario podría devolver una lista no vacía. Pero esto no es una prueba.
Lo que queremos decir es que fes uniforme : si siempre devuelve la lista vacía para bool list, entonces tiene que devolver la lista vacía para unit listy, en general, cualquier 'a list. Esto es exactamente de lo que trata el segundo punto en la lista de viñetas al comienzo de mi respuesta.
El artículo nos dice que en ML fdebe tomar valores relacionados con valores relacionados . No voy a entrar en detalles sobre las relaciones, es suficiente decir que las listas están relacionadas si y solo si tienen la misma longitud y sus elementos están relacionados por pares (es decir, [x_1, x_2, ..., x_m]y [y_1, y_2, ..., y_n]están relacionados si y solo si m = ny x_1están relacionados con y_1y x_2está relacionado con y_2y así sucesivamente). Y la parte divertida es, en nuestro caso, dado que fes polimórfico, ¡ podemos definir cualquier relación en los elementos de las listas!
Vamos a recoger cualquier 'a, 'by miran f : 'a list -> 'b list. Ahora mira f : 'a list -> bool list; Ya hemos demostrado que en este caso fsiempre devuelve la lista vacía. Ahora postulamos que todos los elementos de 'aestán relacionados entre sí (recuerde, podemos elegir cualquier relación que queramos), esto implica que cualquiera zs : 'a listestá relacionado con sí mismo. Como sabemos, ftoma valores relacionados con valores relacionados, esto significa que f zs : 'b listestá relacionado con f zs : bool list, pero la segunda lista tiene una longitud igual a cero, y dado que la primera está relacionada con ella, también está vacía.
Para completar, mencionaré que hay una sección sobre el impacto de la recursividad general (posible no terminación) en el documento original de Wadler, y también hay un documento que explora teoremas libres en presencia de seq.