Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/380.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 程序化无尾递归消除_Javascript_Recursion_Lisp_Scheme - Fatal编程技术网

Javascript 程序化无尾递归消除

Javascript 程序化无尾递归消除,javascript,recursion,lisp,scheme,Javascript,Recursion,Lisp,Scheme,我正在用JavaScript制作一个玩具Lisp解释器。JS没有尾部递归消除(TRE),所以我在JS中使用while循环实现了TRE(伪代码): 所以我很高兴,像下面这样的尾部递归函数不会耗尽堆栈: (define + (lambda (n m) (cond ((zero? n) m) (else (+ (sub1 n) (add1 m)))))) (+ 10000 1) ;=> 10001 但是,不是尾部递归的函数会耗尽JS堆栈(因为JS代码在eval

我正在用JavaScript制作一个玩具Lisp解释器。JS没有尾部递归消除(TRE),所以我在JS中使用while循环实现了TRE(伪代码):

所以我很高兴,像下面这样的尾部递归函数不会耗尽堆栈:

(define +
  (lambda (n m)
    (cond ((zero? n) m)
          (else (+ (sub1 n) (add1 m))))))

(+ 10000 1) ;=> 10001
但是,不是尾部递归的函数会耗尽JS堆栈(因为JS代码在
eval\u操作数上递归太多了)

如何处理非尾部递归函数?有哪些选择?什么是好的资源?我读过一些关于蹦床、堆栈外部化和连续传递样式的书,但我所能找到的只是如何用这些样式编写代码,而不是如何使用这些技术编写解释器。

如果您能够在其他地方保存调用帧信息,则始终可以将调用转换为跳转。这就是“堆栈外部化”所指的

对于您的解释器,您的调用帧数据需要保存非尾部调用的延续(它本身可能保存进一步的引用,例如它需要访问的任何变量)。每个活动的非尾部呼叫将需要一个呼叫帧


当然,所有这些都是用堆栈空间交换堆空间。最后,这样做并不会真正节省内存。:-)

您是否可以编写一些伪代码(例如,以我的eval伪代码为基础)?由于您正在实现一个解释器,性能对您来说应该不是问题,因此您可以先执行CPS转换(然后所有调用都将是尾部调用)。解释CPSed代码很容易,只需使用链表传递延续。请务必阅读FUNARG问题。:)
(define +
  (lambda (n m)
    (cond ((zero? n) m)
          (else (+ (sub1 n) (add1 m))))))

(+ 10000 1) ;=> 10001
(define +
  (lambda (n m)
    (cond ((zero? n) m)
          (else (add1 (+ (sub1 n) m)))))  ; not proper tail-recursive

(+ 10000 1) ;=> JS: Maximum call stack size exceeded