I wanted to have a tail-recursive version of List.map
, so I wrote my own. Here it is:
let rec list_map f l ?(accum=[])=
match l with
head :: tail -> list_map f tail ~accum:(head :: accum)
| [] -> accum;;
Whenever I compile this function, I get:
File "main.ml", line 69, characters 29-31:
Warning X: this optional argument cannot be erased.
The tutorial says that this means that I'm trying to create a function with no non-optional arguments. But the function above clearly takes non-optional arguments.
I'm probably just doing something really dumb, but what?
Yeah your non-optional argument can't be last, because since OCaml supports partial applications, a function missing a last optional argument will just look like a partially-applied function which is still looking for the optional argument. The only way for it to tell that you don't intend to provide the optional argument is that it sees that you have provided an argument after it.
If you have to have it last, you can put a dummy unit
argument after it:
let rec list_map f l ?(accum=[]) () =
match l with
head :: tail -> list_map f tail ~accum:(head :: accum) ()
| [] -> accum;;
But in this case yeah changing the order would be better.
The previous solutions do compile, but won't give the expected result. The function f
is never applied to the arguments. A correct code is:
let rec list_map f ?(accum = []) l = match l with
| head :: tail -> list_map f ~accum:(f head :: accum) tail
| [] -> accum;;
The inferred type is:
val list_map : ('a -> 'b) -> ?accum:'b list -> 'a list -> 'b list = <fun>
... in contrast to the wrong one:
val list_map : 'a -> ?accum:'b list -> 'b list -> 'b list = <fun>
Please note, that the result list is reversed:
# list_map ( ( ** ) 2.) [1.;2.;3.;4.];;
- : float list = [16.; 8.; 4.; 2.]
... and equals the function rev_list from the List module:
# List.rev_map ( ( ** ) 2.) [1.;2.;3.;4.];;
- : float list = [16.; 8.; 4.; 2.]
So you may want to change your function into:
let rec list_map f ?(accum = []) l = match l with
| head :: tail -> list_map f ~accum:(f head :: accum) tail
| [] -> List.rev accum;;
... which should be tail-recursive as well (according to the manual) and returns the list in the original order:
# list_map ( ( ** ) 2.) [1.;2.;3.;4.];;
- : float list = [2.; 4.; 8.; 16.]
You need a non-optional argument after the optional one. Just change the order of the arguments of your function:
let rec list_map f ?(accum=[]) l=
match l with
head :: tail -> list_map f ~accum:(head :: accum) tail
| [] -> accum;;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With