Estoy aprendiendo programación en ML (OCaml), y antes pregunté sobre las funciones de tipo ML'a -> 'b . Ahora he estado experimentando un poco con funciones de tipo 'a list -> 'b list. Hay algunos ejemplos simples obvios:
let rec loop l = loop l
let return_empty l = []
let rec loop_if_not_empty = function [] -> []
| l -> loop_if_not_empty l
Lo que no puedo entender es cómo hacer una función que haga algo más que devolver la lista vacía o el bucle (sin usar ninguna función de biblioteca). Se puede hacer esto? ¿Hay alguna manera de devolver listas no vacías?
Editar: Sí, si tengo una función de tipo 'a -> 'b, entonces puedo hacer otra, o una función de tipo 'a list -> 'b list, pero lo que me pregunto aquí es cómo hacer la primera.
programming-languages
typing
functional-programming
Gilles 'SO- deja de ser malvado'
fuente
fuente

Respuestas:
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:
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 funcionesg : 'a -> 'c,h : 'b -> 'dtenemos:(Nota,
fa la izquierda tiene tipo'a list -> 'b listyfa la derecha es'c list -> 'd list).Somos libres de elegir lo
gque queramos, así que deja'a = 'cyg = id. Ahora desdemap id = id(fácil de probar por inducción en la definición demap), tenemos:Ahora deja
'b = 'd = boolyh = not. Asumamos que para algunoszs : bool listsucede esof zs ≠ [] : bool list. Está claro quemap not ∘ f = fno se sostiene, porqueSi el primer elemento de la lista de la derecha es
true, entonces, a la izquierda, el primer elemento esfalsey viceversa.Esto significa que nuestra suposición es incorrecta y
f zs = []. ¿Terminamos? No.Asumimos que
'besbool. Hemos demostrado que cuandofse invoca con typef : 'a list -> bool listpara any'a,fsiempre debe devolver la lista vacía. ¿Puede ser que cuando llamamosfyaf : '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 parabool list, entonces tiene que devolver la lista vacía paraunit 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 sim = nyx_1están relacionados cony_1yx_2está relacionado cony_2y así sucesivamente). Y la parte divertida es, en nuestro caso, dado quefes polimórfico, ¡ podemos definir cualquier relación en los elementos de las listas!Vamos a recoger cualquier
'a,'by miranf : 'a list -> 'b list. Ahora miraf : 'a list -> bool list; Ya hemos demostrado que en este casofsiempre 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 cualquierazs : 'a listestá relacionado con sí mismo. Como sabemos,ftoma valores relacionados con valores relacionados, esto significa quef zs : 'b listestá relacionado conf 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.fuente
gyhen este caso) ir directamente con las relaciones generales a medida ...Volvamos a los objetos más simples: no puede construir un objeto de tipo adecuado
'aporque entonces significaría que este objetoxse puede usar donde sea'aque encaje. Y eso significa en todas partes: como un entero, una matriz, incluso una función. Por ejemplo, eso significaría que puede hacer cosas comox+2,x.(1)y(x 5). Los tipos existen exactamente para evitar esto.Esta es la misma idea que se aplica con una función de tipo
'a -> 'b, pero hay algunos casos en los que este tipo puede existir: cuando la función nunca devuelve un objeto de tipo'b: cuando se repite o se genera una excepción.Esto también se aplica a las funciones que devuelven una lista. Si su función es de tipo
t -> 'b listy crea un objeto de tipoty lo aplica a esta función, eso significa que si accede con éxito a un elemento de esta lista, accederá a un objeto que tenga todos los tipos. Por lo tanto, no puede acceder a ningún elemento de la lista: la lista está vacía o ... no hay lista.Sin embargo, el tipo
'a list -> 'b listaparece en los ejercicios habituales, pero eso es solo cuando ya tiene una función de tipo'a -> 'b:Pero probablemente conozcas este.
fuente
'a -> 'bo'a list -> 'b list, pero esa no es una observación tan interesante. De hecho, voy a editar la pregunta para dejar en claro que esto no es de lo que se preguntaba la programación de aprendizaje para estudiantes más jóvenes.f : 'a list -> 'b listyttal quef t <> []entonces este programa escribirá-cheque, pero puede hacer camino peor que lanzar una excepción:let y = List.hd (f t) in (y y) (y + y.(0) + y.(0).(0)).Teorema de parametricidad de los "Teoremas gratis!" El artículo nos dice que los términos de ML tienen una propiedad muy especial: si vemos el tipo de un término como una relación con los valores de este tipo, entonces el valor de este término estará relacionado con sí mismo. Aquí se explica cómo ver los tipos como relaciones:
'a -> 'bcorresponde a la relación definida al decir que dos funciones están relacionadas si toman valores relacionados con valores relacionados (asumiendo'ay'bcorresponden a algunas relaciones).'a listcorresponde a la relación definida al decir que dos listas están relacionadas si tienen la misma longitud y sus elementos coincidentes están relacionados (suponiendo que'acorresponda a alguna relación).Aquí hay un ejemplo. Supongamos que tenemos un términoUNA1 y UNA2 , elige absolutamente cualquier relación UNA entre elementos de este tipo, y si tomamos alguno una1:UNA1 y una2:UNA2 , de modo que estén relacionados de acuerdo con UNA , entonces foouna1 y foouna2 también estará relacionado de acuerdo a UNA :
foo : 'a -> 'a. El teorema de la parametricidad dice quefooestá relacionado con sí mismo. Lo que esto significa es que podemos elegir dos tipos, digamos,Ahora si tomamos la relaciónUNA no ser una relación arbitraria, sino una función F:UNA1→UNA2 , lo anterior se convierte en:
o, en otras palabras:
que es exactamente el teorema libre para la
idfunción:f . id = id . f.Si realiza pasos similares para su funciónUNA1 y UNA2 , cualquier relación UNA entre sus elementos, cualesquiera dos tipos si1 y si2 , cualquier relación si entre sus elementos, luego tome dos listas, primero hechas de elementos de UNA1 , segundo hecho de elementos de UNA2 , aplique su función a ambas listas (obtener una lista de si1 en el primer caso y una lista de si2 en el segundo), y los resultados estarán relacionados, si las entradas estaban relacionadas.
foo : 'a list -> 'b list, obtendrá que puede elegir dos tiposAhora usamos esto para probar que para cualquiera de los dos tipos
AyBla funciónfoodevuelve una lista vacía para cualquier entradaas : A list.Ay dejaØ,Byasestá relacionado con sí mismo (como elegimos la relación de identidadA), por lo tantofoo as : Ø listestá relacionado confoo as : B list.Øtipo.Por lo tanto, para cualquiera
A,Byas : A listtenemos quefoo as : B listtiene que ser una lista vacía.fuente