树中的原子数

时间:2017-02-18 08:20:35

标签: lisp common-lisp

我不明白以下段落:

  

(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?

你能解释一下吗?

2 个答案:

答案 0 :(得分:4)

如果您想在运行时构建(a (b) c),只使用consquote,您可以写:

(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))))))
  • 遇到原子时,结果为1。
  • 如果你有一个cons单元,你可以将其汽车中的原子数和cdr相加。

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