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

为什么这个Lisp函数总是给我一个堆栈溢出?,lisp,Lisp,此功能在此处: (defun test (a) (if (equal a nil) 0) (if (listp (car a)) (print "a") (print "b")) (test (cdr a)) ) 如果a是nil,我希望它返回0,这是基本情况。然后,如果列表前面的元素是列表,则打印字母a,否则打印b,然后再次调用函数。为什么基

此功能在此处:

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

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

因为基本情况之后仍然是打印和递归。之后它没有直接返回

也许你想要这个:

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

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

请注意,您可以使用null进行nil检查。 如果a不是零,那么并且只有在那时,a才被进一步检查。为此,progn允许您计算表达式序列,并最终计算为最后一个表达式的结果。
其他答案很好地解释了你的问题;只有两个注释:

康德

至少有一个风格指南建议不要使用if和preferencecond;这本可以避免跌落问题:

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

您可以从函数中提前返回;您的代码将使用returnfrom子句:


我几乎要投你一票了,但是你的if缩进被取消了。标准缩进是将then和else与测试在同一个缩进处对齐。我已经有很长一段时间没有做任何与Lisp相关的事情了,但我看到它是双向的。有没有类似于权威风格指南的东西?我倾向于使用,尽管它不是特定于CL的。但即使是常见的lisp缩进也同意这一点。谢谢你的推荐。我同意并会解决这个问题。好的,这就是我想做的。。。如果nil返回0 else如果a是list print a else如果a不是list print b返回函数,且cdr aIn实现执行尾部调用优化,那么这将是一个无限循环。
(defun test (a)
  (if (null a)
      0
      (progn
        (if (listp (car a))
            (print "a")
            (print "b"))
        (test (cdr a)))))
(defun test (a)
  (cond
   ((equal a nil) 0)
   (t (if (listp (car a)) 
        (print "a")
        (print "b"))
      (test (cdr a)))))
(defun test (a)
  (if (equal a nil) (return-from test 0))
  (if (listp (car a)) 
    (print "a")
    (print "b"))
  (test (cdr a)))