为什么这个Lisp函数不断给我一个堆栈溢出?

时间:2014-02-18 10:20:04

标签: lisp

这个功能在这里:

(defun test (a)
               (if (equal a nil) 0)
               (if (listp (car a)) (print "a")
                 (print "b"))
               (test (cdr a))
               )

如果0a这是基本情况,我希望它返回nil。然后,如果列表前面的元素是列表,则打印字母a否则打印b然后再次调用函数。为什么基本情况不会阻止无限循环?

3 个答案:

答案 0 :(得分:3)

您的代码最终会出现堆栈溢出,因为无论test检查结果如何,都会递归到nil

(defun test (a)
  (if (equal a nil) 0)  ; <-- problem is partly here...
  (if (listp (car a))
      (print "a")
      (print "b"))
  (test (cdr a)))       ; <-- ...and partly down here

即使(equal a nil)评估为T且周围的if评估为0,您基本上也会忽略此结果,因为您要做的下一步是检查{是否{ {1}}是一个列表,无论前一个a检查结果如何。最后,您再次致电nil而不考虑比较结果。

请记住,Lisp中函数的结果是最后一次计算表达式的结果,这意味着如果您希望函数返回test,则必须使0成为最后一个计算表达式

以下代码的行为与您指定的相同:

0
  • 请注意,您可以使用(defun test (a) (if (null a) 0 (progn (if (listp (car a)) (print "a") (print "b")) (test (cdr a))))) 进行零检查。
  • 如果null不是a,那么只有这样,才会进一步检查nil。为此,a允许您评估表达式序列,并最终计算其最后一个表达式的结果。

答案 1 :(得分:3)

其他答案很好地解释了你的问题;只有2个音符:

<强> COND

至少有一个样式指南建议使用 if 并且喜欢 cond ;这样可以避免&#34;掉头问题&#34;:

(defun test (a)
  (cond
   ((equal a nil) 0)
   (t (if (listp (car a)) 
        (print "a")
        (print "b"))
      (test (cdr a)))))

<强>返回

您可以从功能中提前返回;您的代码可以使用 return-from 子句:

(defun test (a)
  (if (equal a nil) (return-from test 0))
  (if (listp (car a)) 
    (print "a")
    (print "b"))
  (test (cdr a)))

答案 2 :(得分:1)

因为您的基本案例仍然是打印和递归。之后它没有直接回归。

也许你想要这个:

(defun test (a)
  (if (null a)
      0
      (progn (if (listp (car a))
                 (print "a")
                 (print "b"))
             (test (cdr a)))))