编写一个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的新手,所以这种类型的系统让我很困惑
答案 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
。
类型参数'b
为string
,因为您需要处理字符串列表。
因此,在您的情况下,函数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的工作原理了。由于这显然是一个家庭作业问题,我将把这个任务留给你。