为什么 apply 会在大列表上抛出 CONTROL-STACK-EXHAUSTED-ERROR?

Ker*_*nic 2 sbcl common-lisp

(apply #'+ (loop for i from 1 to x collect 1))
Run Code Online (Sandbox Code Playgroud)

如果x具有 value 则有效253391,但(SB-KERNEL::CONTROL-STACK-EXHAUSTED-ERROR)253392*上失败。这比call-arguments-limit**小几个数量级。

递归是否耗尽了堆栈?如果是这样,它在apply吗?怎么还没优化?


*也很有趣,(apply #'max (loop for i from 1 to 253391 collect 1))抛出错误,但253390很好。

**call-arguments-limit计算结果为 4611686018427387903(在format's的帮助下~R,这是四千亿六百一十亿六千八千六万亿十八四亿七千七百七千九百三

Rai*_*wig 5

可以传递给 SBCL 函数的参数

你不传递参数。你传递参数

(defun foo (x y) (list x y))
Run Code Online (Sandbox Code Playgroud)

xy是函数的参数foo

(foo 20 22)
Run Code Online (Sandbox Code Playgroud)

2022函数调用中的参数foo

查看变量call-arguments-limitlambda-parameters-limit

SBCL 和调用参数限制

如果一个函数几乎不能处理声称的参数数量,那么这看起来像是SBCL. 您可能想报告此错误。也许他们需要更改call-arguments-limit.

测试

APPLY 是测试它的一种方法。

其他:

(eval (append '(drop-params)
               (loop for i from 1 to 2533911 collect 1)))
Run Code Online (Sandbox Code Playgroud)

还可以将 FUNCALL 与多个参数展开一起使用。

为什么存在极限?

编写 Common Lisp 标准是为了允许在各种不同的计算机上高效实现。人们认为某些机器级函数调用实现仅支持有限数量的参数。该标准表示支持的参数数量可以低至50. 实际上,一些实现支持的参数数量相对较少。

因此,apply在 Common Lisp 中,它不是用于列表处理的工具,而是用于调用带有计算参数列表的函数。

对于列表和向量处理使用 REDUCE,而不是 APPLY

如果我们想对列表中的所有数字求和,请替换

(apply #'+ list)     ; don't use this
Run Code Online (Sandbox Code Playgroud)

(reduce #'+ list)    ; can handle arbitrary long lists
Run Code Online (Sandbox Code Playgroud)

递归

apply 是一个非优化的递归函数

我不明白为什么函数APPLY应该使用递归。

例如,如果你想到

(apply #'+ '(1 2 3 4 5))
Run Code Online (Sandbox Code Playgroud)

参数的重复求和由函数完成,+而不是由 完成apply

这不同于

(reduce #'+ '(1 2 3 4 5))
Run Code Online (Sandbox Code Playgroud)

其中+带有两个参数的函数的重复调用由reduce.