你的两个问题是相关的。 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 是 OCaml 中“lambda”的符号,即函数字面量。
函数fun h t -> fn h :: t 有两个值h 和t。它将函数fn 应用于h,并在t 的前面返回一个带有这个新值的新列表。
从打字的角度来看,h 的值必须是正确的类型才能传递给fn,fn 必须返回正确类型的值才能在列表t 中。
如果这样更清楚,您可以像这样用括号括起来: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 并不是一种特殊的函数。它与任何其他功能完全一样。这只是一个符号选择。