1

服务器下面的代码显示列表中的整数个数。

(defun isNum (N)
  (and (<= N 9) (>= N 0)))

(defun count-numbers (list)
  (let ((count 0))
    (dolist (item list count)
      (cond
       ((null list) nil)
       (((and (<= N 9) (>= N 0))) item)(incf count))
       (setq(0 + count))))))

运行命令时出现错误A' is not of the expected typeREAL' (count-numbers '(3 4 5 6 a 7 b) )

4

2 回答 2

6

我很惊讶它的运行,因为你cond的构造不正确,你在代码的不必要的副作用生成位中切换到中缀表示法,并且你在count-numbers. 假设,如果它确实运行,该错误听起来是正确的。您正在对参数进行数字比较(以及非数字输入上的错误)。

我今天戴上了 codereview 帽子,所以让我们更深入地了解一下。


Lisp(实际上并不重要,afaik 这适用于 CL、Scheme 和所有杂种)使用lower-case-snake-case-with-dashes,而不是lowerCamelCase用于变量和函数名称。

(defun is-num (n)
  (and (<= n 9) (>= n 0)))

常见的 Lisp 约定是以 结束谓词,p而不-p是以 . 开头is-。Scheme具有(IMO更好)结束谓词的约定,?而不是

(defun num-p (n)
  (and (<= n 9) (>= n 0)))

((and (<= N 9) (>= N 0)))不是你调用函数的方式。您实际上需要使用它的名称,而不仅仅是尝试调用它的主体。如果您尝试运行此代码,这是您会遇到的许多错误之一。

(defun count-numbers (list)
  (let ((count 0))
    (dolist (item list count)
      (cond
       ((null list) nil)
       ((num-p item) item)(incf count))
       (setq(0 + count))))))

numberp已经存在,并对其输入进行类型检查,而不是尝试进行数字比较。您可能应该改用它。

(defun count-numbers (list)
  (let ((count 0))
    (dolist (item list count)
      (cond
       ((null list) nil)
       ((numberp item) item)(incf count))
       (setq(0 + count))))))

((numberp item) item) (incf count))可能不会像您认为它作为cond子句那样做。它实际上被视为两个单独的子句;检查是否item是 a number,如果是则返回。第二个尝试检查变量incf并返回count它是否评估为t(它没有,也不会)。您似乎想要的是count当您在列表中找到一个数字时增加计数器,这意味着您应该将该incf子句与item.

(defun count-numbers (list)
  (let ((count 0))
    (dolist (item list count)
      (cond ((null list) nil)
            ((numberp item) 
             (incf count)
             item))
      (setq (0 + count)))))

(setq (0 + count))是错误的事情有三个原因

  • 您似乎回到了中缀符号,这意味着第二位实际上是在尝试0使用变量+count作为参数调用函数。
  • 您没有第二部分setq,这意味着您正在尝试将上述内容设置为NIL隐式。
  • 您实际上不需要设置任何内容即可返回值

至此,我们终于有了一段可以正确评估和运行的代码(并且它不会抛出您上面提到的错误)。

(defun count-numbers (list)
  (let ((count 0))
    (dolist (item list count)
      (cond ((null list) nil)
            ((numberp item) 
             (incf count)
             item))
      count)))

dolist是一个迭代构造,它为给定列表中的每个元素做一些事情。这意味着您实际上不需要使用 that 手动测试列表终止cond。此外,因为dolist不收集结果,所以没有理由返回item它。您还不必要地隐藏了count您在let.

(defun count-numbers (list)
  (let ((count 0))
    (dolist (item list)
      (when (numberp item) (incf count)))
    count))

像往常一样,您可以通过更简单的loop调用来完成所有这些操作。

(defun count-numbers (list)
  (loop for item in list
        when (numberp item) sum 1))

这使计数器隐含并避免您需要手动返回它。事实上,除非这是专门编写您自己的迭代函数的练习,否则 Common Lisp 有一个内置的count-if,它接受predicate sequence [some other options]并返回匹配count项中的。如果你想具体命名,出于文体原因,你可以sequencepredicatecount-numbers

(defun count-numbers (list) (count-if #'numberp list))

并完成它。


总之,很好的尝试,但在提出进一步的问题之前,请尝试阅读语言家族知识

于 2012-07-10T14:36:53.223 回答
0

另一种方法是:

(reduce
 #'(lambda (a b)
     (if (numberp b) (1+ a) a))
 '(3 4 5 6 a 7 b) :initial-value 0) ; 5

即以在每次迭代中为您提供前一次迭代的结果+序列的下一个成员的方式处理序列。从零开始,每次序列中的元素为数字时递增结果。

编辑

抱歉,我还没有看到 Inaimathi 提到过count-if。那可能会更好。

于 2012-07-11T09:38:33.227 回答