递归函数如何在Lisp中工作?

时间:2015-11-01 13:25:47

标签: recursion lisp common-lisp

所以我在Lisp编码,我想出了一个计算列表中原子数的函数(没有子列表)。所以代码是这样的:

(defun num-atoms (list)
  (cond
    ((null list) 0)
    ((atom list) 1)
    (t (+ (num-atoms (car list))
          (num-atoms (cdr list))))))

这对我来说很有意义。因此,如果我在参数中使用列表(1 2 3)调用此函数,则应如下所示:

  • (num-atoms'(1 2 3))
  • not null
  • not atom
  • NUM-原子(1)
  • atom so return 1
  • num-atoms((2 3))
  • not null
  • not atom
  • num-atoms(2)
  • return 1
  • ....

但是,如果我写这样的代码:

(defun num-atoms (list)
  (cond
    ((null list) 0)
    ((atom list) 1)
    (t (+ (num-atoms (cdr list))
          (num-atoms (car list))))))

这里我刚刚在最后一行切换了de car和cdr位置。

它仍然有效!如果我做一个跟踪,它会给我相同顺序的原子数!它在'(1 2 3)列表中首先计算1,依此类推。 有人可以向我解释这个代码的第二版仍然有效吗?我真的不明白这里的逻辑。

1 个答案:

答案 0 :(得分:4)

如果你trace这两个功能,你会看到他们的差异。

在第一个版本中,原子按顺序处理,因为函数处理第一个元素(car),然后处理其余元素(cdr)。

在第二个版本中,原子以相反的顺序获得进程,因为函数在处理第一个元素之前首先处理剩余的元素。所以找到的第一个原子是列表中的最后一个,然后堆栈展开。

但当然结果在两种情况下都相同,因为加法是commutative

* (defun num-atoms(list)
  (cond
   ((null list) 0)
   ((atom list) 1)
   (t (+ (num-atoms (car list)) (num-atoms (cdr list))))))

NUM-ATOMS
* (trace num-atoms)

(NUM-ATOMS)
* (num-atoms '(1 2 3))
  0: (NUM-ATOMS (1 2 3))
    1: (NUM-ATOMS 1)
    1: NUM-ATOMS returned 1
    1: (NUM-ATOMS (2 3))
      2: (NUM-ATOMS 2)
      2: NUM-ATOMS returned 1
      2: (NUM-ATOMS (3))
        3: (NUM-ATOMS 3)
        3: NUM-ATOMS returned 1
        3: (NUM-ATOMS NIL)
        3: NUM-ATOMS returned 0
      2: NUM-ATOMS returned 1
    1: NUM-ATOMS returned 2
  0: NUM-ATOMS returned 3
3

* (defun num-atoms(list)
  (cond
   ((null list) 0)
   ((atom list) 1)
   (t (+ (num-atoms (cdr list)) (num-atoms (car list))))))

NUM-ATOMS
* (num-atoms '(1 2 3))
  0: (NUM-ATOMS (1 2 3))
    1: (NUM-ATOMS (2 3))
      2: (NUM-ATOMS (3))
        3: (NUM-ATOMS NIL)
        3: NUM-ATOMS returned 0
        3: (NUM-ATOMS 3)
        3: NUM-ATOMS returned 1
      2: NUM-ATOMS returned 1
      2: (NUM-ATOMS 2)
      2: NUM-ATOMS returned 1
    1: NUM-ATOMS returned 2
    1: (NUM-ATOMS 1)
    1: NUM-ATOMS returned 1
  0: NUM-ATOMS returned 3
3
*