Recursion 为什么这个函数在无限循环学习lisp中
(编辑:我还不打算担心TCO) 我(终于开始)学习Lisp了。我正在尝试编写自己的(幼稚的)函数来压平列表。我从简单的案例开始,如果它不起作用,我将构建它来处理更复杂的案例。不幸的是,现在,我得到了一个无限循环,不太明白为什么 我也不知道如何在lisp中使用任何调试方法,所以如果你也能告诉我这个方向,我将不胜感激Recursion 为什么这个函数在无限循环学习lisp中,recursion,lisp,infinite-loop,Recursion,Lisp,Infinite Loop,(编辑:我还不打算担心TCO) 我(终于开始)学习Lisp了。我正在尝试编写自己的(幼稚的)函数来压平列表。我从简单的案例开始,如果它不起作用,我将构建它来处理更复杂的案例。不幸的是,现在,我得到了一个无限循环,不太明白为什么 我也不知道如何在lisp中使用任何调试方法,所以如果你也能告诉我这个方向,我将不胜感激 (defun flattenizer (lst) (if (listp (car lst)) (flattenizer (car lst)) (if (null l
(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)
(listp NIL)
返回T
,(listp(car NIL))
,因此当您到达列表末尾并在NIL
上递归时,会发生循环
您需要更改测试的顺序,首先测试(null lst)
,以避免循环。最好用cond
重新编写。使用cond
更容易更改测试顺序
然后你会注意到,出于某种原因,你只展平了参数列表中的第一个元素。在((1 2)(3 4))
等中的(3 4)
怎么样。?我们真的应该以某种方式将平整汽车
的结果与平整cdr
的结果结合起来
如果展平列表的结果是一个列表,那么我们需要合并两个结果列表。此外,由于我们将合并列表,如果遇到原子,我们将不得不生成一个列表,作为平坦化该原子的结果。使用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 (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] 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] 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] 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] 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] 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
*
现在检查您的源代码。
NIL
在Common Lisp中有点“奇怪”,因为它既有实际原因,也有历史原因。例如:
是一个符号:NIL
(symbolp NIL)==>T
是一个列表:NIL
(listp NIL)==>T
不是cons单元格:NIL
(consp NIL)==>NIL
- 但是你可以把它当作
/car
:cdr
和(carnil)==>NIL
(cdrnil)==>NIL
在您的代码中,当
(listp(car x))
导致无限递归时,递归调用(car x)
,因为NIL
是一个列表,而它的car
本身就是它。+谢谢你给了我提示而没有给我答案。我有一种感觉,我必须像对待树一样对待嵌套列表,并沿着每个分支递归。这就是(曾经)所谓的“car-cdr”递归——最基本、最低效的递归我会调用变量LST
只是LIST
。我也会先使用FIRST
和REST
,而不是CAR
和CDR
。感谢我处于无限循环中的明确原因。非常有用。