13

我想有一个尾递归版本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.

教程说这意味着我正在尝试创建一个没有非可选参数的函数。但是上面的函数显然需要非可选参数。

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

4

3 回答 3

20

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

如果你必须把它放在最后,你可以unit在它后面加上一个虚拟参数:

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

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

于 2009-11-03T15:05:25.213 回答
12

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

let rec list_map f ?(accum=[]) l=
  match l with
    head :: tail -> list_map f  ~accum:(head :: accum) tail
  | [] -> accum;;
于 2009-11-03T13:09:44.743 回答
4

以前的解决方案可以编译,但不会给出预期的结果。该函数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.]

...并等于List 模块中的函数 rev_list

# 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.]
于 2009-12-02T12:33:55.610 回答