Jas*_*ker 9 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;;
Run Code Online (Sandbox Code Playgroud)
每当我编译这个函数时,我得到:
File "main.ml", line 69, characters 29-31:
Warning X: this optional argument cannot be erased.
Run Code Online (Sandbox Code Playgroud)
该教程说这意味着我正在尝试创建一个没有非可选参数的函数.但上面的函数显然采用了非可选参数.
我可能只是在做一些非常愚蠢的事情,但是什么呢?
new*_*cct 16
是的,你的非可选参数不能是最后的,因为由于OCaml支持部分应用程序,缺少最后一个可选参数的函数看起来就像是部分应用的函数,它仍然在寻找可选参数.它告诉你不打算提供可选参数的唯一方法是它看到你在它之后提供了一个参数.
如果你必须持续它,你可以unit在它后面放一个伪参数:
let rec list_map f l ?(accum=[]) () =
match l with
head :: tail -> list_map f tail ~accum:(head :: accum) ()
| [] -> accum;;
Run Code Online (Sandbox Code Playgroud)
但在这种情况下,改变顺序会更好.
Pas*_*uoq 12
在可选参数之后需要一个非可选参数.只需更改函数参数的顺序:
let rec list_map f ?(accum=[]) l=
match l with
head :: tail -> list_map f ~accum:(head :: accum) tail
| [] -> accum;;
Run Code Online (Sandbox Code Playgroud)
以前的解决方案确实可以编译,但不会给出预期的结果。该函数f永远不会应用于参数。正确的代码是:
let rec list_map f ?(accum = []) l = match l with
| head :: tail -> list_map f ~accum:(f head :: accum) tail
| [] -> accum;;
Run Code Online (Sandbox Code Playgroud)
推断的类型是:
val list_map : ('a -> 'b) -> ?accum:'b list -> 'a list -> 'b list = <fun>
Run Code Online (Sandbox Code Playgroud)
...与错误的相反:
val list_map : 'a -> ?accum:'b list -> 'b list -> 'b list = <fun>
Run Code Online (Sandbox Code Playgroud)
请注意,结果列表是相反的:
# list_map ( ( ** ) 2.) [1.;2.;3.;4.];;
- : float list = [16.; 8.; 4.; 2.]
Run Code Online (Sandbox Code Playgroud)
...并且等于List 模块中的函数rev_list :
# List.rev_map ( ( ** ) 2.) [1.;2.;3.;4.];;
- : float list = [16.; 8.; 4.; 2.]
Run Code Online (Sandbox Code Playgroud)
所以你可能想将你的函数更改为:
let rec list_map f ?(accum = []) l = match l with
| head :: tail -> list_map f ~accum:(f head :: accum) tail
| [] -> List.rev accum;;
Run Code Online (Sandbox Code Playgroud)
...这也应该是尾递归的(根据手册)并按原始顺序返回列表:
# list_map ( ( ** ) 2.) [1.;2.;3.;4.];;
- : float list = [2.; 4.; 8.; 16.]
Run Code Online (Sandbox Code Playgroud)