2

编写一个 Ocaml 函数list_print : string list -> unit,从左到右打印列表中的所有字符串:

所以假设我有一个 Ocaml 函数list_print: string list -> unit,它打印列表中的所有字符串,从左到右写入。现在正确的解决方案是:

let list_print lst = List.fold_left (fun ( ) -> fun s -> print_string s) () lst;;

但是在编写我的解决方案时,我是这样写的:

let list_print lst = List.fold_left (fun s -> print_string s) () lst;;

但这给了我

错误:此表达式具有单元类型,但预期的表达式类型为 'a -> string

为什么我需要第一个参数 fun() -> 在 fun 之前?我还是 Ocaml 的新手,所以这种类型系统让我很困惑

4

2 回答 2

8

fold_left(and )的目的fold_right是在您进行过程中累积一个值。额外的参数是这个累积值。

你可以使用List.iter你的问题。它不会累积价值。

您可以将其List.iter视为List.fold_left累积 type 值的版本unit。而且,事实上,你可以这样实现它:

let iter f = List.fold_left (fun () a -> f a) ()

要点(与 总是一样unit)是该类型只有一个值,因此它表示该值不感兴趣的情况。

于 2012-10-09T02:16:40.567 回答
1

您想使用List.fold_left,这很好,但您应该从阅读该函数的文档开始。官方文档很短:

val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
List.fold_left f a [b1; ...; bn] is f (... (f (f a b1) b2) ...) bn.

首先是该函数的类型。类型是

 ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a

换句话说,该函数fold_left具有三个参数和一个结果值。第一个参数有 type ('a -> 'b -> 'a)。第二个参数有 type 'a。第三个参数有 type 'b list。函数的结果值类型为'a

现在,在您的情况下,您想要打印字符串。所以你实际上不需要任何结果值,你需要一个副作用。但是,在 OCaml 中,所有函数都必须有一个结果值。因此,您使用空值 ,()它的类型为unit。因此,在您的情况下,类型参数'a将等于unit

类型参数'bstring因为您需要处理字符串列表。

因此,在您的情况下,函数fold_left必须具有类型

 (unit -> string -> unit) -> unit -> string list -> unit.     

的第一个参数fold_left必须具有类型unit->string->unit。换句话说,它必须是一个有两个参数的函数,第一个参数是空值,即(),第二个参数是一个字符串。所以第一个参数fold_left必须是这种函数,

 fun x y -> ...

wherex必须是 typeunitytype string。因为x总是等于(),所以没有必要把这个参数写成一个变量x,相反我们可以简单地写()甚至是哑参数_。(语法fun x -> fun y -> ...提供与 相同的功能fun x y -> ...。)

现在你可以开始弄清楚 fold_left 是如何工作的。由于这显然是一个家庭作业问题,我将把这个任务留给你。

于 2012-10-10T08:07:30.680 回答