2009-11-03 18 views
8

Quería tener una versión recursiva de List.map, así que escribí la mía. Aquí está:El argumento opcional no se puede borrar?

let rec list_map f l ?(accum=[])= 
    match l with 
     head :: tail -> list_map f tail ~accum:(head :: accum) 
    | [] -> accum;; 

Siempre que puedo compilar esta función, me sale:

File "main.ml", line 69, characters 29-31: 
Warning X: this optional argument cannot be erased. 

El tutorial dice que esto significa que estoy tratando de crear una función sin argumentos no opcionales. Pero la función anterior claramente toma argumentos no opcionales.

Probablemente estoy haciendo algo realmente tonto, pero ¿qué?

+1

debería echar un vistazo a las publicaciones recientes en la lista de correo ocaml sobre mapas recursivos de cola. http://groups.google.com/group/fa.caml/browse_thread/thread/8b2a70a767e6a433 – nlucaroni

Respuesta

3

Las soluciones anteriores se compilan, pero no darán el resultado esperado. La función f nunca se aplica a los argumentos. Un código correcto es:

let rec list_map f ?(accum = []) l = match l with 
    | head :: tail -> list_map f ~accum:(f head :: accum) tail 
    | [] -> accum;; 

El tipo inferido es:

val list_map : ('a -> 'b) -> ?accum:'b list -> 'a list -> 'b list = <fun> 

... en contraste con el equivocado:

val list_map : 'a -> ?accum:'b list -> 'b list -> 'b list = <fun> 

Tenga en cuenta, que el resultado la lista está invertida:

# list_map ((**) 2.) [1.;2.;3.;4.];; 
- : float list = [16.; 8.; 4.; 2.] 

... y es igual a la función rev_list from the List module:

# List.rev_map ((**) 2.) [1.;2.;3.;4.];; 
- : float list = [16.; 8.; 4.; 2.] 

por lo que puede que desee cambiar su función en:

let rec list_map f ?(accum = []) l = match l with 
    | head :: tail -> list_map f ~accum:(f head :: accum) tail 
    | [] -> List.rev accum;; 

... que debe ser recursiva de cola, así (según el manual) y devuelve la lista en el orden original:

# list_map ((**) 2.) [1.;2.;3.;4.];; 
- : float list = [2.; 4.; 8.; 16.] 
12

Necesita un argumento no opcional después de el opcional. Sólo cambia el orden de los argumentos de la función:

let rec list_map f ?(accum=[]) l= 
    match l with 
    head :: tail -> list_map f ~accum:(head :: accum) tail 
    | [] -> accum;; 
+1

Muchas gracias.Ese me va a hacer tropezar mucho. Estoy acostumbrado a hacer que los argumentos opcionales sean los últimos como Python y C++ requiere. :-( –

13

Sí su argumento no opcional no puede ser la última, ya que desde OCaml es compatible con aplicaciones parciales, una función que falta un último argumento opcional sólo se verá como una función parcialmente aplicada que todavía está buscando el argumento opcional. La única forma de que diga que no tiene la intención de proporcionar el argumento opcional es que ve que ha proporcionado un argumento después.

Si usted tiene que tener la última, se puede poner un argumento ficticio unit después de que:

let rec list_map f l ?(accum=[])() = 
    match l with 
     head :: tail -> list_map f tail ~accum:(head :: accum)() 
    | [] -> accum;; 

Pero en este caso, sí cambiar el orden sería mejor.

+0

Entonces la aplicación de la función también necesita el argumento dummy '()'. – weakish

Cuestiones relacionadas