可选参数不能被删除?

时间:2009-11-03 13:05:32

标签: ocaml compiler-warnings optional-arguments

我想要一个List.map的尾递归版本,所以我写了自己的版本。这是:

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

每当我编译这个函数时,我得到:

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

tutorial表示这意味着我正在尝试创建一个没有非可选参数的函数。但上面的函数显然采用了非可选参数。

我可能只是在做一些非常愚蠢的事情,但又是什么?

3 个答案:

答案 0 :(得分:15)

是的,你的非可选参数不能是最后的,因为由于OCaml支持部分应用程序,缺少最后一个可选参数的函数看起来就像是部分应用的函数,它仍在寻找可选参数。它告诉你不打算提供可选参数的唯一方法是它看到你之后提供了一个参数。

如果你必须持续它,你可以在它之后放一个虚拟的unit参数:

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

但在这种情况下,改变顺序会更好。

答案 1 :(得分:12)

在可选参数之后需要一个非可选参数。 只需更改函数参数的顺序:

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

答案 2 :(得分:3)

以前的解决方案会编译,但不会给出预期的结果。函数f永远不会应用于参数。正确的代码是:

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

推断类型是:

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

...与错误的相反:

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

请注意,结果列表是相反的:

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

...等于函数rev_list from the List module

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

所以你可能想把你的功能改成:

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

...也应该是尾递归的(根据手册)并按原始顺序返回列表:

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