Ocaml中的List.Fold_Left类型系统?

时间:2012-10-09 01:44:29

标签: list ocaml fold higher-order-functions

编写一个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 - >串

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

2 个答案:

答案 0 :(得分:8)

fold_left(和fold_right)的目的是随着时间的推移累积一个值。额外参数是此累计值。

您可以使用List.iter解决问题。它累积值。

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

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

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

答案 1 :(得分: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有三个参数和一个结果值。第一个参数的类型为('a -> 'b -> 'a)。第二个参数的类型为'a。第三个参数的类型为'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 -> ...

其中x必须是unit类型,y类型string。由于x总是等于(),因此没有必要将此参数写为变量x,而只需编写()甚至虚拟对象参数_。 (语法fun x -> fun y -> ...提供与fun x y -> ...相同的功能。)

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