为什么这个函数处于无限循环中 - 学习lisp

时间:2013-02-26 20:13:00

标签: recursion lisp infinite-loop

(编辑:我还没有担心TCO)

我(最后到处)学习Lisp。我试图编写自己的(天真)功能来压缩列表。我从较简单的案例开始,如果它不起作用,将构建它以处理更复杂的案例。不幸的是,我现在得到了一个无限循环,并且无法弄清楚原因。

我也不知道如何在lisp中使用任何调试方法,所以如果你能指出我的方向,我也会很感激。

(defun flattenizer (lst)
  (if (listp (car lst))
    (flattenizer (car lst))
    (if (null lst)
      nil
      (cons (car lst) (flattenizer (cdr lst))))))

最终代码:

(defun flattenizer (lst)
  (cond
    ((null lst) nil)
    ( (consp (car lst)) 
        (nconc (flattenizer (car lst)) (flattenizer (cdr lst)) ))
    (T (cons (car lst) (flattenizer (cdr lst))))))

测试:

* (flattenizer '((1 2) (3 4)))

(1 2 3 4)
* (flattenizer '(1 (2 3) (4 5)))

(1 2 3 4 5)
* (flattenizer '((1 2) 3 (4 5) 6))

(1 2 3 4 5 6)
* (flattenizer '(1 2 3 4))

(1 2 3 4)

3 个答案:

答案 0 :(得分:6)

(listp NIL)返回T(listp (car NIL))也是如此,因此当您点击列表末尾并递归NIL时,就会发生循环。

您需要更改测试的顺序,首先测试(null lst),以避免循环。最好用cond重写它。使用cond更改测试顺序更容易。

然后您会注意到,由于某种原因,您只会在参数列表中展平第一个元素。 (3 4)((1 2) (3 4))怎么样?我们应该以某种方式将展平car的结果与展平cdr的结果结合起来。

如果将列表展平的结果是列表,那么我们需要将两个结果列表组合在一起。此外,由于我们将组合列表,如果我们遇到一个原子,我们将不得不生成一个列表,作为扁平化原子的结果。

答案 1 :(得分:5)

由于实际和历史原因的混合,

NIL在Common Lisp中有点“奇怪”。例如:

  • NIL是一个符号:(symbolp NIL) ==> T
  • NIL是一个列表:(listp NIL) ==> T
  • NIL 一个利弊单元格:(consp NIL) ==> NIL
  • 但您仍然可以car / cdr(car NIL) ==> NIL(cdr NIL) ==> NIL

(car x)导致无限递归时,(listp (car x))会递归调用代码,因为NIL是一个列表而car本身就是。

答案 2 :(得分:4)

使用SBCL进行调试。

告诉SBCL你想要调试:

* (proclaim '(optimize (debug 3)))

您的代码:

* (defun flattenizer (lst)
    (if (listp (car lst))
      (flattenizer (car lst))
      (if (null lst)
        nil
        (cons (car lst) (flattenizer (cdr lst))))))

FLATTENIZER

使用STEP

进行步调
* (step (flattenizer '(1 (2 3) 4)))
; Evaluating call:
;   (FLATTENIZER '(1 (2 3) 4))
; With arguments:
;   (1 (2 3) 4)

下一步

1] step
; Evaluating call:
;   (FLATTENIZER (CDR LST))
; With arguments:
;   ((2 3) 4)

下一步

1] step
; Evaluating call:
;   (FLATTENIZER (CAR LST))
; With arguments:
;   (2 3)

下一步

1] step
; Evaluating call:
;   (FLATTENIZER (CDR LST))
; With arguments:
;   (3)

下一步

1] step
; Evaluating call:
;   (FLATTENIZER (CDR LST))
; With arguments:
;   NIL

下一步

1] step
; Evaluating call:
;   (FLATTENIZER (CAR LST))
; With arguments:
;   NIL

下一步

1] step
; Evaluating call:
;   (FLATTENIZER (CAR LST))
; With arguments:
;   NIL

现在看起来像是在循环中。

回到顶层。

1] top

*

现在检查您的源代码。