为什么Emacs lisp中没有尾递归优化,而不是像其他方案一样?

Why is there no tail recursion optimization in Emacs lisp, not but like other scheme?

Emacs lisp 是 LISP 的一种方言,尤其是 Scheme。大多数方案解释器确实有尾递归的优化,但 emacs lisp 没有。我在`info elisp'里找了好久都没找到

P.S。是的,在 elisp 中还有其他迭代语法,如 `while',但我仍然找不到他们没有像其他方案解释器那样实现尾递归的充分理由。

Emacs Lisp 创建于 1980 年代。 Emacs 作者(Richard Stallman)当时最熟悉的 Lisp 方言是 MIT Maclisp,Emacs Lisp 与其非常相似。它使用动态变量作用域,没有词法闭包或尾递归优化,Emacs Lisp 也一样。

Emacs Lisp 与 Scheme 有很大的不同。最大的区别是 Scheme 是词法范围的,但这只是最近才添加到 Emacs Lisp 中,并且必须在每个文件的基础上启用(通过将 ;;; -*- lexical-binding: t -*- 放在第一行)因为默认情况下这样做会导致很多不兼容。

用 Guile(一种 Scheme 方言)替换 Emacs Lisp 已经有一些工作。但是否能开花结果还不得而知。

Emacs Lisp 在其生命的头 25 年里一直将动态范围作为其 main/only 范围规则。动态作用域基本上与尾递归的优化不兼容,所以直到 Emacs-24(引入了词法作用域),人们对这种优化几乎没有兴趣。

如今,ELisp 有时可以从尾递归的优化中获益,并且已经提交了一些补丁来做到这一点,但尚未集成。尾递归优化的缺乏以及函数调用的相对低效实现影响了 ELisp 风格,以至于递归不经常使用,这反过来又降低了添加尾调用优化的好处。

看起来有人在 Emacs Lisp 中实现了 TCO:https://github.com/Wilfred/tco.el。我自己还没有玩过它,但如果您有兴趣了解 Emacs Lisp 中的 TCO,您可能想试一试。

Emacs 28 引入了宏 named-let,可用于以优化的方式计算 tail-recursive 循环表达式。

虽然还没有直接支持 auto-optimizing 函数,但我们可以在这些函数中使用上面的宏;或者,如果您喜欢冒险,请将 native-comp-speed 设置为 3(也包括 Emacs 28+):Self TCO by GCCEmacs