你说:
我不明白这个功能是如何工作的。不是每个map函数都需要一个函数和一个列表吗?
好吧,请记住,在标准 ML(以及一般情况下,所有应用语言)中,对于除 1 之外的“n”,没有“n 个参数的函数”之类的东西。但是,可以通过两种方式模拟多个参数:
作为元组或记录的单个参数的函数。通过元组或记录的投影,可以在函数体中恢复原始预期参数。
作为第一个参数的函数,返回其余参数的函数。
考虑到这一点,我们在 REPL 中检查map 的类型:
> map;
val it = fn: ('a -> 'b) -> 'a list -> 'b list
(我使用 Poly/ML,而不是 SML/NJ,但除了格式问题,输出应该是相同的。)
没有元组,没有记录。 map 显然采用第二种方法来模拟两个参数的函数:它采用 'a -> 'b 类型的函数并返回 另一个 'a list -> 'b list 类型的函数。
现在,问题来了:对于任何函数foo,map foo 也是一个函数!由于map 可以将any 函数作为参数,因此map foo 本身就是map 的完全合法参数。这意味着map (map foo) 对任何函数foo 进行类型检查。特别是,如果val foo = fn x => [x] 是这样。
你说:
似乎没有足够的参数来实际执行。
如果它进行类型检查,它就会运行。
你说:
如果我跑步
map (fn x => [x]) [[], [1], [2,3,4]]
我明白了
val it = [[[]], [[1]], [[2,3,4]]];
这对我来说更有意义,因为它获取列表中的每个元素,并将其包装在另一个列表中。但是当我在上面放另一张地图时,它会改变输出。
让我们在不改变其含义的情况下稍微重构您的代码:
let
val foo = fn x => [x]
val bar = map foo
val baz = map bar
in
baz [[], [1], [2,3,4]]
end
现在我们可以分析每个函数(foo、bar、baz)对其参数做了什么:
-
foo 采用单个元素 x 并将其包装在列表数据构造函数中。
-
bar 获取一个元素列表,将每个元素包装在一个列表数据构造函数中,并返回一个包含结果包装元素的列表(列表列表)。
-
baz 获取元素(子)列表的(超)列表,将bar 应用于每个子列表,并返回一个包含结果的列表。
手动执行所有这些操作,让自己相信结果 [[], [[1]], [[2], [3], [4]]] 确实是正确的。