【问题标题】:Why is this function in an infinite loop - learning lisp为什么这个函数会死循环——学习lisp
【发布时间】:2013-02-12 10:47:24
【问题描述】:

(编辑:我还不会担心 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)

【问题讨论】:

  • 我将变量称为LST 只是LIST。我也会使用FIRSTREST 而不是CARCDR

标签: recursion lisp infinite-loop


【解决方案1】:

(listp NIL) 返回T(listp (car NIL)) 也是如此,所以当你到达列表末尾并递归NIL 时,就会发生循环。

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

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

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

【讨论】:

  • 太棒了。 +1 给我提示而不给我答案。我有一种感觉,我必须将嵌套列表视为一棵树,并沿每个分支递归。
  • 这就是(曾经)所谓的“car-cdr”递归——最基本但效率最低的。 :)
【解决方案2】:

NIL 在 Common Lisp 中有点“奇怪”,原因有很多。例如:

  • NIL 是一个符号:(symbolp NIL) ==> T
  • NIL 是一个列表:(listp NIL) ==> T
  • NIL 不是缺点单元:(consp NIL) ==> NIL
  • 但无论如何你都可以使用car/cdr(car NIL) ==> NIL(cdr NIL) ==> NIL

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

【讨论】:

  • 感谢我处于无限循环中的明确原因。很有帮助。
【解决方案3】:

使用 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

*

现在检查您的源代码。

【讨论】:

    猜你喜欢
    • 2011-04-14
    • 2022-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-28
    • 1970-01-01
    • 2018-02-19
    • 1970-01-01
    相关资源
    最近更新 更多