理解fold_right的机制

时间:2017-11-03 04:52:17

标签: ocaml higher-order-functions fold

问题:定义第一个参数是一元函数的函数mapf和第二个参数列表。结果是应用于参数列表的每个元素的函数列表。使用fold_right写一个单行,而不是递归函数。

解决方案:

let mapf fn list = fold_right (fun h t -> fn h :: t) list []

我不明白这是如何解决问题的,因为fold_right以递归的方式使用list参数计算函数,因此它返回一个值而不是一个列表。我不明白以下符号的含义:

fun h t -> fn h :: t

1 个答案:

答案 0 :(得分:4)

你的两个问题是相关的。 fold_right返回一个值是正确的,但列表是一个值!

::运算符将新元素添加到列表的开头。因此,fold_right的此应用程序计算的值确实是一个列表。

另一种思考方式可能如下。如果您将fold_right+运算符一起使用,则可以计算如下值:

fold_right (+) [1; 2; 3] 0 =>
1 + 2 + 3 + 0 =>
6

如果您对fold_right运算符使用::,则计算如下值:

fold_right (::) [1; 2; 3] [] =>
1 :: 2 :: 3 :: [] =>
[1; 2; 3]

这不是理论上的,它在REPL中的作用与此类似:

# List.fold_right (+) [1; 2; 3] 0;;
- : int = 6
# List.fold_right (fun a b -> a :: b) [1; 2; 3] [];;
- : int list = [1; 2; 3]

(您需要写fun a b -> a :: b,因为::符号实际上不能用作独立函数。不幸的是。)

请注意,自己使用::运算符编写列表是完全合法的:

# 1 :: 2 :: 3 :: [];;
- : int list = [1; 2; 3]

<强>更新

首先,fun x y -> expr是&#34; lambda&#34;的标记。在OCaml中,即函数文字。

函数fun h t -> fn h :: t有两个值ht。它将函数fn应用于h,并在t的前面返回一个包含此新值的新列表。

从打字的角度来看,值h必须是传递给fn的正确类型,而fn必须返回列表中t的正确类型的值1}}。

你可以这样括起来:fun h t -> (fn h) :: t,如果这样可以更清楚。

函数fun a b -> a :: b类似,只是它将a直接放到列表b上。它不适用任何功能。从本质上讲,它只是::运算符所做的事情。

从打字的角度来看,a必须是正确的类型才能成为列表b的元素。

更新2

如果你试图了解lambda是什么,一种看待它的方法是,它只是一种编写功能相当小的方便的方法。您可以轻松编写没有lambda的给定代码:

let mapf fn list =
    let helper h t = fn h :: t in
    List.fold_right helper list []

此版本具有名为helper的本地声明函数。

,而不是lambda

另一种看待它的方式是所有函数都是lambdas。编写函数的惯用方法:

let f x y = x + y

只是具有显式lambda的版本的简便缩写:

let f = fun x y -> x + y

所以,实际上,lambda并不是一种特殊的功能。它与任何其他功能完全一样。这只是一个符号选择。