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