你说:
我不明白这个功能是如何工作的。不是每个地图函数都需要一个函数和一个列表吗?
好吧,请记住,在标准 ML(以及一般来说,所有应用语言)中,对于除 1 之外的“n”,没有“n 个参数的函数”之类的东西。但是,多个函数可以通过两种方式模拟参数:
作为作为元组或记录的单个参数的函数。通过从元组或记录中进行投影,可以在函数体中恢复原始预期参数。
作为第一个参数的函数,返回其余参数的函数。
考虑到这一点,我们检查mapREPL 中的类型:
> 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可以将任何函数作为参数,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]]]确实是正确的。