-1

ECL 可以计算 fac(1000) 真是太棒了!ECL 怎么做呢?

 >(defun fac (n) (if (= n 1) 1 (* n (fac (- n 1)))))
 >(disassemble #'fac)
 #(FAC N = - * #<bytecompiled-function FAC> SI:FSET)
 Name:           FAC                                                                 
    0    POP     REQ
    1    BIND    N
    3    NOMORE
    4    PUSHV   0
    6    PUSH    1
    8    CALLG   2,=
   11    JNIL    18
   13    QUOTE   1
   15    SET     VALUES(0),REG0
   16    JMP     35
   18    PUSHV   0
   20    PUSHV   0
   22    PUSH    1
   24    CALLG   2,-
   27    PUSH    VALUES(0)
   28    CALLG   1,FAC
   31    PUSH    VALUES(0)
   32    CALLG   2,*
   35    EXIT

我对 ECL 字节码知之甚少。似乎没有尾递归优化。有高手能解释一下吗?

真挚地!

4

2 回答 2

3

ECL 的解释器目前不做尾调用优化。它可以很容易地实现,但我没有时间去做:基本上它相当于在字节码编译器中添加一个标志来表示尾调用。在任何情况下,正如这里所指出的,ECL 解释器使用动态分配的堆栈,以及用于解释器递归的 C 堆栈。这意味着您将获得大约 1000 个 C 堆栈帧(小)和一些简洁的列表来跟踪环境。目前它就足够了,没关系。但是,在 C 端,ECL 确实检测到自身的尾调用并可以优化其中的许多,并且在其他情况下,GCC 会优化相互尾调用(对位于尾部位置的其他函数的调用)。

于 2012-09-25T14:17:49.457 回答
0

我对 ECL 一无所知,但我从您编译的源代码中看到,然后在反汇编中看到,编译器可以正常工作。该函数被定义为对自身的递归调用。我在拆卸时看到的一样。因此,在调用此函数期间可能出现的唯一问题是堆栈溢出和算术溢出。

于 2012-09-19T01:22:21.550 回答