所以我在Lisp编码,我想出了一个计算列表中原子数的函数(没有子列表)。所以代码是这样的:
(defun num-atoms (list)
(cond
((null list) 0)
((atom list) 1)
(t (+ (num-atoms (car list))
(num-atoms (cdr list))))))
这对我来说很有意义。因此,如果我在参数中使用列表(1 2 3)
调用此函数,则应如下所示:
但是,如果我写这样的代码:
(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,依此类推。 有人可以向我解释这个代码的第二版仍然有效吗?我真的不明白这里的逻辑。
答案 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
*