Ocaml 中的 List.Fold_Left 类型系统?

Posted

技术标签:

【中文标题】Ocaml 中的 List.Fold_Left 类型系统?【英文标题】:List.Fold_Left type system in Ocaml? 【发布时间】:2012-09-29 07:08:36 【问题描述】:

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

但这给了我

错误:此表达式的类型为 unit,但表达式的类型应为 'a -> string

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

【问题讨论】:

【参考方案1】:

fold_left(和fold_right)的目的是在你前进的过程中积累一个价值。额外的参数就是这个累加值。

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

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

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

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

【讨论】:

【参考方案2】:

您想使用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 是如何工作的。既然这显然是一道作业题,我就把这个任务留给你。

【讨论】:

以上是关于Ocaml 中的 List.Fold_Left 类型系统?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Ocaml 中使用类中定义的类型作为 val?

OCaml和OCaml评估模型中的功能应用列表

OCaml 中的依赖类型

OCaml中的主要功能

OCaml 中的“and”关键字是啥意思?

OCaml 中的 D 类不可变数据切片