根据 Common Lisp HyperSpec (CLHS),
mapcan
使用 nconc
将其结果组合成一个列表。 CLHS 也这么说
(mapcon f x1 ... xn)
== (apply #'nconc (maplist f x1 ... xn))
所以我一直担心在
apply
很低的情况下使用 call-arguments-limit
的后果 - CLHS 说它可以低至 50,而在 LispWorks 上它是 2047。在 LispWorks 上,
(mapcan #'list (loop for i from 0 to call-arguments-limit collect i))
成功,而
(apply #'nconc (mapcar #'list (loop for i from 0 to call-arguments-limit collect i)))
失败。如果
mapcan
真的必须使用nconc
,这两个不应该都失败吗?
规范的一个重点是1.4.3 部分不是本标准的正式部分,其中特别指出示例仅供说明使用,不是标准的一部分。
通常在 HyperSpec 中,展示如何用另一个构造表达一个构造的示例旨在展示函数的意图,并且可以假设该示例适用于一些没有物理限制(如内存等)的抽象实现
没有requirement
MAPCAN
或MAPCON
以此处显示的确切方式使用NCONC
,事实上我认为没有==
的正式定义(技术上代码也使用省略号,因此它不是用 Common Lisp 编写的)。
一个更好的例子是使用
REDUCE
来 NCONC
连续的结果,甚至是 LOOP
。我认为在这个例子中使用APPLY
是不幸的,但最终你可以假设MAPCON
和MAPCAN
都不受CALL-ARGUMENTS-LIMIT
的限制。
例如,你可以这样表达,但实际的
MAPCAN
可能不需要像MAPCAR
那样分配中间列表,它可以只是融合两个操作:
(reduce #'nconc (mapcar f x1 .. xn))
引用自标准:
和mapcan
分别像mapcon
和mapcar
,不同之处在于应用函数的结果通过使用maplist
而不是nconc
组合成一个列表。list
那么,是否意味着
mapcar
必须由(apply #'list ...)
执行?别傻了,当然没必要。这意味着mapcar
调用的函数的结果以与list
相同的方式组合成一个列表:通过构建cons单元链,其汽车指向返回值。
完全相同的方式,
mapcan
调用的函数返回的结果按照nconc
的方式组合,即它们必须是列表并且这些列表被破坏性地连接起来。
这就是标准中语言的意思。