(编辑:我还没有担心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)
答案 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
*
现在检查您的源代码。