2009-11-03 19 views
8

Volevo avere una versione ricorsiva in coda di List.map, quindi ho scritto la mia. Eccolo:L'argomento facoltativo non può essere cancellato?

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

Ogni volta che compilo questa funzione, ottengo:

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

Il tutorial dice che questo significa che sto cercando di creare una funzione senza argomenti non opzionali. Ma la funzione sopra accetta chiaramente argomenti non opzionali.

Probabilmente sto solo facendo qualcosa di veramente stupido, ma cosa?

+1

dovresti dare un'occhiata ai post recenti sulla mailing list ocaml sulle mappe ricorsive di coda. http://groups.google.com/group/fa.caml/browse_thread/thread/8b2a70a767e6a433 – nlucaroni

risposta

3

Le soluzioni precedenti vengono compilate, ma non forniscono il risultato previsto. La funzione f non viene mai applicata agli argomenti. Un codice corretto è:

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

Il tipo derivato è:

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

... in contrasto con quella sbagliata:

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

Si prega di notare, che il risultato la lista è invertita:

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

... ed è pari alla funzione di rev_list from the List module:

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

quindi si consiglia di cambiare la funzione in:

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

... che dovrebbe essere ricorsiva in coda pure (secondo il manuale) e restituisce la lista nell'ordine originale:

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

È necessario un argomento non facoltativo dopo lo quello facoltativo. Basta cambiare l'ordine degli argomenti della vostra funzione:

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

Grazie mille.Questo mi farà inciampare molto. Sono abituato a fare in modo che gli argomenti opzionali siano gli ultimi richiesti da Python e C++. :-( –

13

Già il vostro argomento non opzionale non può essere l'ultima, perché da OCaml supporta applicazioni parziali, una funzione manca un ultimo argomento opzionale sarà solo l'aspetto di un funzione parzialmente applicata che sta ancora cercando l'argomento opzionale. L'unico modo per dire che non si intende fornire l'argomento opzionale è che vede che è stato fornito un argomento dopo di esso.

Se si deve avere l'ultima, si può mettere un unit argomento fittizio dopo che è:

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

Ma in questo caso sì cambiando l'ordine sarebbe meglio.

+0

Quindi, per applicare la funzione è necessario anche l'argomento dummy '()'. – weakish

Problemi correlati