ANSI Common Lisp 允许实现限制可传递给函数的参数的最大数量。该限制由下式给出调用参数限制 http://clhs.lisp.se/Body/v_call_a.htm可以小至 50。
对于行为类似于代数群运算符的函数,遵循
关联属性(+
, list
等),我们可以通过使用来绕过限制reduce
在将函数视为二进制时抽取输入列表。
例如添加一个大的数字列表:(reduce #'+ list)
而不是(apply #'+ list)
.
注意事项reduce
在 Common Lisp 中,reduce
即使列表为空也似乎可以工作。很少有其他语言可以给你这个,而且它实际上并不是来自reduce
:它不适用于所有功能。但与+
我们可以写(reduce #'+ nil)
它计算为零,就像(apply #'+ nil)
.
这是为什么?因为+
函数可以使用零参数调用,并且当使用零参数调用时,它会生成加法群的单位元:0
。这与reduce
功能。
在其他一些语言中fold
or reduce
函数必须被赋予一个初始种子值(例如0
),否则是一个非空列表。如果两者都没有给出,那就是一个错误。
通用 Lispreduce
,如果给出一个空列表并且没有:initial-value
,将不带参数调用内核函数,并使用返回值作为初始值。由于该值是唯一的值(列表为空),因此返回该值。
请注意最左侧参数具有特殊规则的函数。例如:
(apply #'- '(1)) -> -1 ;; same as (- 1), unary minus semantics.
(reduce #'- '(1)) -> 1 ;; what?
发生的事情是当reduce
给定一个单元素列表,它只返回元素而不调用函数。
基本上它是建立在上面提到的数学假设之上的,如果没有:initial-value
然后提供f
预计会支持(f) -> i
, where i
是一些与相关的单位元f
, 以便(f i x) -> x
。这在减少单例列表时用作初始值,(reduce #'f (list x)) -> (f (f) x) -> (f i x) -> x
.
The -
函数不遵守这些规则。(- a 0)
意思是“从a
” 所以产量a
, 然而(- a)
是加法逆元a
,可能纯粹出于实用的、符号的原因(即,不让 Lisp 程序员编写(- 0 a)
只是为了翻转一个标志,只是为了拥有-
在以下情况下表现得更加一致reduce
and apply
). The -
函数也不能用零参数调用。
如果我们想获取一个数字列表并将它们全部从某个值中减去x
,其模式是:
(reduce #'- list-of-numbers :initial-value x)