我不明白以下段落:
(COUNT-ATOMS'(A(B)C))应该返回五。
A,B和C以及树中的两个NIL。
编写一个函数COUNT-ATOMS,它返回树中的原子数。
我试过了:
(defun count-atoms(l)
(cond
((null l) 0)
(t (+ (cond
((atom (car l)) 1)
(t 0))
(count-atoms (cdr l))))))
但是,(COUNT-ATOMS '(A (B) C))
返回2。
我应该怎么做才能返回5?
你能解释一下吗?
答案 0 :(得分:4)
如果您想在运行时构建(a (b) c)
,只使用cons
和quote
,您可以写:
(cons 'a
(cons (cons 'b nil)
(cons 'c nil)))
正在构建的树中有5个原子(a,b,c和两个nil)。在实践中,您可以使用更简单的表示法,例如(list 'a (list 'b) 'c)
。
在你的功能中,你不会进入树木的CARS,只能进入CDRS。此外,当CAR不是原子时,就像遇到(B)
时一样,你加零(第二个cond
中的默认子句)(编辑。正如kmkaplan所说,你也算零为nil,first cond)。
这是一个简单的解决方案,基于typecase
:
(defun count-atoms (form)
(typecase form
(atom 1)
(cons (+ (count-atoms (car form))
(count-atoms (cdr form))))))
typecase
根据其参数类型(form
)进行调度。每个子句都具有以下语法:(type ...body...)
,其中type
是类型的名称,...body...
是一个或多个表达式(隐式progn
):最后一个值是如果参数与类型typecase
匹配,则返回type
的值。
第一个句子(atom 1)
说:如果form是一个原子,则返回1 。以下一个,(cons ...)
说: else,如果form是一个cons单元,... 。这里,atom
是类型的名称,表示不是cons
的所有内容。当然,一旦你知道某些东西不是原子,你知道它必然是cons
,而第二次测试是多余的。但是,它更具可读性,任何体面的编译器都会优化第二个测试。
还有一个名为atom
的函数,它是一个测试值是否为原子的谓词。这就是为什么当你在REPL中自己编写(atom 1)
时,它会返回T.
另请参阅wikipedia和Seibel的 Practical Common Lisp chapter about lists。
答案 1 :(得分:2)
您的功能有两个问题。在coredump's answer中整齐描述的第一个是,COUNT-ATOMS
仅在尾部(CDR
)进行递归,并且忘记在你的cons小区的CAR
元素上进行递归({ {1}})。因此,它无法计算L
原子。
第二个问题是,当B
为原子时,您将NIL
计算为0
,应计为1
。