List 如何用lisp编写递归?

List 如何用lisp编写递归?,list,recursion,lisp,List,Recursion,Lisp,我需要你的大力帮助。 我想在Lisp中编写一个名为rec的函数,该函数将收到如下列表: 记录'101252921443115 我的代码应该检查内部列表的和是否等于外部列表的数字5+2+2=9等于9,然后我进一步检查9+9+12=30,3+3+1=5等于5,然后5+5+4=14等于14,14+14+2=30,30等于30,至少我把10加到30+30,整个列表的和是70。如果我的和等于这些数字,我将返回整个列表的和,否则我将返回Nil。我希望你明白我的意思…现在我想用递归来解决它,我尝试了一些方法,

我需要你的大力帮助。 我想在Lisp中编写一个名为rec的函数,该函数将收到如下列表: 记录'101252921443115 我的代码应该检查内部列表的和是否等于外部列表的数字5+2+2=9等于9,然后我进一步检查9+9+12=30,3+3+1=5等于5,然后5+5+4=14等于14,14+14+2=30,30等于30,至少我把10加到30+30,整个列表的和是70。如果我的和等于这些数字,我将返回整个列表的和,否则我将返回Nil。我希望你明白我的意思…现在我想用递归来解决它,我尝试了一些方法,但我不能解决它,我希望有人能进一步帮助我

(defun rec(list)

)

(rec '(10 (12 (5 2 2) 9) (2 14 (4 (3 1 1) 5))))


一旦您明确了需要做什么,如何实现该功能将更容易

输入 您的输入是一个列表,但不是任何类型的列表。 让我们将这种特定的列表命名为节点

节点为空列表或3个元素的列表v n1 n2,其中:

v是一个数字, n1分别为。n2是节点或数字。 输出 在节点上调用rec时,它应该输出一个数字或nil

概述 让我们定义一个辅助num函数,该函数通过调用rec获取一个数字或一个节点并返回一个数字或nil:

数字n的num n应返回n 节点n的num n应返回rec n 然后,rec可定义如下:

rec nil应该是nil 当num n1和num n2是相等的数字时,rec v n1 n2应该返回+v num n1 num n2。在任何其他情况下,rec应返回nil。 实例 下面是一种可能的实现方法,它依赖于诸如本地函数定义之类的运算符,基于值的类型和早期返回技术进行切换。另见。使用逻辑运算符和/或有助于组合可能的NIL中间结果:

(defun rec (node)
  (flet ((num-or-fail (n)
           (or (typecase n
                 (number n)
                 (cons (rec n)))
               (return-from rec))))
    (and node
         (destructuring-bind (v n1 n2) node
           (let ((v1 (num-or-fail n1))
                 (v2 (num-or-fail n2)))
             (and (= v1 v2)
                  (+ v v1 v2)))))))
在REPL命令行中,可以为rec激活跟踪:

然后您可以测试:

CL-USER> (rec '(10 (12 (5 2 2) 9) (2 14 (4 (3 1 1) 5))))
上面返回70并在SBCL中打印以下跟踪:

0: (REC (10 (12 (5 2 2) 9) (2 14 (4 (3 1 1) 5))))
  1: (REC (12 (5 2 2) 9))
    2: (REC (5 2 2))
    2: REC returned 9
  1: REC returned 30
  1: (REC (2 14 (4 (3 1 1) 5)))
    2: (REC (4 (3 1 1) 5))
      3: (REC (3 1 1))
      3: REC returned 5
    2: REC returned 14
  1: REC returned 30
0: REC returned 70
提前返回甚至可以从最外层的调用中转义,因为它意味着整个结果是NIL,有点像异常。您也可以将rec设置为本地函数,与num或fail相互递归,并以不同的方式命名主函数:

(defun sumtree (node)
  (labels ((num-or-fail (n)
             (or (typecase n
                   (number n)
                   (cons (rec n)))
                 (return-from sumtree)))
           (rec (node)
             (and node
                  (destructuring-bind (v n1 n2) node
                    (let ((v1 (num-or-fail n1))
                          (v2 (num-or-fail n2)))
                      (and (= v1 v2)
                           (+ v v1 v2)))))))
    (rec node)))
在上面的这里,当中间结果之一为nil时,从的返回将展开整个递归调用堆栈并直接返回nil。

一旦您明确了需要做什么,如何实现该函数将变得更容易

输入 您的输入是一个列表,但不是任何类型的列表。 让我们将这种特定的列表命名为节点

节点为空列表或3个元素的列表v n1 n2,其中:

v是一个数字, n1分别为。n2是节点或数字。 输出 在节点上调用rec时,它应该输出一个数字或nil

概述 让我们定义一个辅助num函数,该函数通过调用rec获取一个数字或一个节点并返回一个数字或nil:

数字n的num n应返回n 节点n的num n应返回rec n 然后,rec可定义如下:

rec nil应该是nil 当num n1和num n2是相等的数字时,rec v n1 n2应该返回+v num n1 num n2。在任何其他情况下,rec应返回nil。 实例 下面是一种可能的实现方法,它依赖于诸如本地函数定义之类的运算符,基于值的类型和早期返回技术进行切换。另见。使用逻辑运算符和/或有助于组合可能的NIL中间结果:

(defun rec (node)
  (flet ((num-or-fail (n)
           (or (typecase n
                 (number n)
                 (cons (rec n)))
               (return-from rec))))
    (and node
         (destructuring-bind (v n1 n2) node
           (let ((v1 (num-or-fail n1))
                 (v2 (num-or-fail n2)))
             (and (= v1 v2)
                  (+ v v1 v2)))))))
在REPL命令行中,可以为rec激活跟踪:

然后您可以测试:

CL-USER> (rec '(10 (12 (5 2 2) 9) (2 14 (4 (3 1 1) 5))))
上面返回70并在SBCL中打印以下跟踪:

0: (REC (10 (12 (5 2 2) 9) (2 14 (4 (3 1 1) 5))))
  1: (REC (12 (5 2 2) 9))
    2: (REC (5 2 2))
    2: REC returned 9
  1: REC returned 30
  1: (REC (2 14 (4 (3 1 1) 5)))
    2: (REC (4 (3 1 1) 5))
      3: (REC (3 1 1))
      3: REC returned 5
    2: REC returned 14
  1: REC returned 30
0: REC returned 70
提前返回甚至可以从最外层的调用中转义,因为它意味着整个结果是NIL,有点像异常。您也可以将rec设置为本地函数,与num或fail相互递归,并以不同的方式命名主函数:

(defun sumtree (node)
  (labels ((num-or-fail (n)
             (or (typecase n
                   (number n)
                   (cons (rec n)))
                 (return-from sumtree)))
           (rec (node)
             (and node
                  (destructuring-bind (v n1 n2) node
                    (let ((v1 (num-or-fail n1))
                          (v2 (num-or-fail n2)))
                      (and (= v1 v2)
                           (+ v v1 v2)))))))
    (rec node)))

在上面的这里,当中间结果之一为nil时,从的返回将展开整个递归调用堆栈并直接返回nil。

对于我来说,似乎唯一可行的方法是如果所有列表都有3个元素。我们称之为三倍

德芬三联肽e 和Listpe =3长度e ;; 测验 三步5;==>无 三步'3 4 5;==>T 我不喜欢rec这个名字,所以我叫它sum triple。我猜:

三重和5;==>5. 和三元组'3 1;==> 让x2和三重1 x3和三1 如果=x2 x3 +三重和3 x2 x3 0 现在要让它返回“你需要包装它”。第一个调用需要与所有其他调用不同,以便您可以跳出帮助程序,在需要时执行完全不同的操作:

解除我的乐趣 标签辅助器x acc;acc在这里只是为了表明你可以保持状态 ;; 调用自身的实际实现 ;; 如果它发现一个坏值,它可以用 从我的乐趣中归来 助手x' 为了 在我看来,如果所有列表都有3个元素,这似乎是唯一可行的方法。我们称之为三倍

德芬三联肽e 和Listpe =3长度e ;; 测验 三步5;==>无 三步'3 4 5;==>T 我不喜欢rec这个名字,所以我叫它sum triple。我猜:

三重和5;==>5. 和三元组'3 1;==> 让x2和三重1 x3和三1 如果=x2 x3 +三重和3 x2 x3 0 现在要让它返回“你需要包装它”。第一个调用需要与所有其他调用不同,以便您可以跳出帮助程序,在需要时执行完全不同的操作:

解除我的乐趣 标签辅助器x acc;acc在这里只是为了表明你可以保持状态 ;; 调用自身的实际实现 ;; 如果它发现一个坏值,它可以用 从我的乐趣中归来 助手x'
请注意,该示例故意使用了学生不应该知道的功能,而不仅仅是复制。请注意,该示例故意使用了学生不应该知道的功能,而不仅仅是复制。