Common Lisp 中的递归与应用?

Vin*_*inn 2 recursion common-lisp apply

当我出于学习目的阅读代码时,我经常看到这样的函数:

(defun min-list (lst)
  (cond ((endp (rest lst)) (first lst))
    (t
     (min (first lst) (min-list (rest lst))))))

Run Code Online (Sandbox Code Playgroud)

如果我在我的项目中编写这个函数,我会用apply.

(defun min-list2 (lst)
  (cond ((endp (rest lst)) (first lst))
    (t
     (apply #'min lst))))))
Run Code Online (Sandbox Code Playgroud)

当我用 测试这两个变体时time,它们似乎执行相同的操作。

有关系吗?

Sva*_*nte 7

他们使用不同的风格,但有不同的限制。

递归变体,正如它所写的那样,受到堆栈空间的限制(如果列表太长,有时会出现堆栈溢出)。可以将其重写为尾递归,在大多数 CL 实现中,尾递归将被优化为或多或少的不会增加堆栈的循环,但这不能保证可移植代码。

apply变体受到 的限制call-arguments-limit,标准仅保证其至少为 50,尽管大多数实现的值要高得多。通常最好显式使用reduce

另一种也是惯用的解决方案是使用loopdo或某些库(例如iterate或 )直接循环for,这些通常是性能最高的(在重要的情况下)。