我最近多年来第一次搞乱计划。 我使用repl.it来玩一下。 我写了这个基本函数来获取一个列表并返回一个双向链表。列表中的每个单元格都是一对,其汽车是列表元素,其cdr与汽车中的前一个元素和cdr中的下一个元素成对。第一个和最后一个元素分别为前一个和下一个项目。我写的函数是尾递归的。我现在知道该方案实际上确实有循环语法,但当我写它时,我的印象是循环方案的唯一方法是使用尾递归。我的代码如下:
(define (dbllink li)
(letrec ((step (lambda (lis prev head)
(if (null? lis)
head
(let ((cell (cons (car lis)
(cons prev '()))))
(if (null? prev)
(step (cdr lis);<--recursive call
cell
cell)
(begin (set-cdr! (cdr prev)
cell)
(step (cdr lis);<--recursive call
cell
head ))))))))
(step li '() '())))
我标记了我认为只有两个递归调用。根据{{3}},他们在我看来都处于尾部上下文中,但调用该函数会导致堆栈溢出。任何想法为什么?
答案 0 :(得分:3)
是。你的代码确实是尾递归的。当我在DrRacket的r6rs中尝试这个时,我得到了
(dbllink '(1 2 3 4 5))
; ==> #0={1 () . #1={2 #0# . #2={3 #1# . #3={4 #2# 5 #3#}}}}
这使得圆形结构。我想也许BiwaScheme尝试打印这个并且你不能打印带有尾递归的列表结构,它也不会检查循环列表,所以最终会出现堆栈溢出。
您可以通过分配结果来验证这一点,以便它不会打印结果。
(define test (dbllink '(1 2 3 4 5)) ; ==> #void
(car test) ; ==> 1
test ; ("too much recursion" in Biwa)