Domanda

ho voluto avere una versione ricorsiva in coda di List.map, così ho scritto la mia. Eccolo:

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 esercitazione dice che questo significa che sto cercando di creare una funzione senza non argomenti -opzionale. Ma la funzione di cui sopra chiaramente prende argomenti non opzionali.

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

È stato utile?

Soluzione

Le soluzioni precedenti non compilano, ma non dà il risultato previsto. La f funzione 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 l'elenco dei risultati è invertito:

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

... ed è pari alla funzione di rev_list da il modulo Lista :

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

Quindi, si può decidere di modificare 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 così (secondo il manuale) e restituisce la lista secondo l'ordine originale:

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

Altri suggerimenti

Sì 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 apparire come una funzione parzialmente applicata, che è ancora alla ricerca per l'argomento opzionale. L'unico modo per lui per dire che non si intende fornire l'argomento opzionale è che si vede che ci avete fornito un argomento dopo di esso.

Se si deve avere l'ultima, si può mettere un argomento fittizio unit 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 stato meglio.

È necessario un argomento non opzionale dopo quello opzionale. 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;;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top