Lisp递归函数在第一次调用时缺少基本情况

时间:2016-04-13 14:19:47

标签: recursion lisp common-lisp

我昨天开始使用lisp编程,所以请原谅我是否犯了一些真正的新手错误。我正在尝试创建一个使用钟形三角形计算钟数的函数,并且我的递归三角函数无法正常工作。我也确定如果我的递归三角函数工作,我的递归钟函数也会以某种方式被破坏。

当我测试我的三角函数时,我得到输出:

(defun bell(l n)
    (if(< n 1)(list 1))
    (if (= n 1)(last l))
    (bell (triangle (reverse l) (last l) (list-length l)) (- n 1))
)
(defun triangle(pL nL i)
    (if(<= i 0)
        (write "equals zero!")
        (reverse nL)
    )
    (triangle pL (append (list (+ (nth i pL) (nth i nL))) nL) (- i 1))  
)
(write (triangle '(1) '(1) 0))


=>


"equals zero!""equals zero!"
*** - NTH: -1 is not a non-negative integer

出于某种原因,它打印我的调试代码两次,即使该函数应该在第一次调用时满足我的基本情况。

3 个答案:

答案 0 :(得分:3)

  

出于某种原因,它打印我的调试代码两次,即使该函数应该在第一次调用时满足我的基本情况。

它被打印两次,因为^[0-9]+$没有按照你的想法做。第一个if测试为真,因此等于零!被打印。之后,调用三角函数的递归调用。测试再次为真(-1 <= 0),因此等于零!再次打印。最后,您会收到错误,因为使用-1调用if函数。我强烈建议你使用一个好的lisp调试器。来自Lispworks的那个非常好。

老实说,我没有弄清楚你想用代码实现的目标。所以我写了我的:

nthcdr

理解实施的事情:

  1. (defun generate-level (l &optional (result)) "given a list l that represents a triangle level, it generates the next level" (if (null l) result (if (null result) (generate-level l (list (car (last l)))) (generate-level (cdr l) (append result (list (+ (car l) (car (last result))))))))) (defun bell (levels &optional (l)) "generate a bell triangle with the number of labels given by the first parameter" (unless (zerop levels) (let ((to-print (if (null l) (list 1) (generate-level l)))) (print to-print) (bell (1- levels) to-print)))) :此参数是可选的,默认为nil。
  2. &optional (parameter)连接两个列表。我正在使用它插入列表的后面。
  3. append创建一个名为let ((to-print x))的新变量绑定(局部变量)并初始化为to-print
  4. 我差点忘了提及x在常见的lisp中是如何工作的: if表示如果(if (= x 1) y z)等于1,则返回x,否则y
  5. 现在,如果你调用函数来创建一个7级的Bell三角形:

    z

    使用适当的填充打印它会更好,如下所示:

    CL-USER 9 > (bell 7)
    
    (1) 
    (1 2) 
    (2 3 5) 
    (5 7 10 15) 
    (15 20 27 37 52) 
    (52 67 87 114 151 203) 
    (203 255 322 409 523 674 877) 
    NIL
    

    但我把它作为练习留给了读者。

答案 1 :(得分:2)

您的 if 没有任何效果。他们被评估,并产生结果,但随后你丢弃它们。就像

(defun abc ()
  'a
  'b
  'c)

会评估'a 'b 以生成符号 a b ,然后评估'c 生成符号 c ,然后返回。在

的情况下
(if(<= i 0)
        (write "equals zero!")  ; then 
        (reverse nL)            ; else
    )

你正在比较 i 是否小于或等于零,如果是,你打印等于零,如果不是,你(非破坏性地)反转nL并丢弃结果。然后通过调用三角形来完成该功能。当i小于或等于零时,您可能希望返回反转的nL。请改用 cond ,因为您可以拥有多个正文表单,例如:

(cond
  ((<= i 0) (write ...) (reverse nL))
  (t (triangle ...)))

您还可以使用 if 预测对表单进行分组:

(if (<= i 0) 
  (progn 
    (write ...)
    (reverse nL))
  (triangle ...))

您的其他功能也有同样的问题。如果要在第一种情况下返回值,则需要使用实际返回它们的表单。例如:

(if (< n 1)
    (list 1)
    (if (= n 1)
        (last l)
        (bell #| ... |#)))

更多惯用语是 cond ,并使用列表而不是 l ,这看起来很像 1

(cond
  ((< n 1) (list 1))
  ((= n 1) (last list))
  (t (bell #| ... |#)))

答案 2 :(得分:-1)

谢谢大家的解释。我最终得到了下面的代码。我意识到if块的工作方式类似于..

(if(condition)(execute statement)(否则执行此语句))

(defun bell(l n)
    (if (< n 2)(last l)
        (bell (triangle l (last l) 0) (- n 1))
    )
)
(defun triangle(pL nL i)
    (if(= i (list-length pL)) nL
        (triangle pL (append  nL (list (+ (nth  i pL) (nth i nL)))) (+ i 1))
    )  
)
(write (bell (list 1) 10))