我在使用 Common Lisp 时遇到了一些麻烦。我想做一个代码来查找列表的值超过或低于两个限制的次数。我想对列表进行扫描并评估当前值是否超过或低于限制。
输出应为包含两个值的列表,列表中大于上限的值的数量和低于下限的值的数量。我尝试使用以下代码:
(defun find-inlist
(y)
(setq upper 0)
(setq lower 0)
(loop for element in y (if (< element 32)(+ lower 1)
(if (> elemen 212)(+ 1 upper))))
(list upper lower))
我使用了以下测试用例,但收到了一条我不明白的错误消息:
> find-inlist '(18 75 31 180 270 52 10 215)
Error: LOOP keyword expected in (... (IF (< ELEMENT 32)
(+ LOWER 1) (IF (> ELEMEN 212) (+ 1 UPPER))))
经过最少编辑的代码的更正形式是:
(defun find-OUTlist ;; NB!! Naming should NOT be misleading
(y
&aux ;; auxiliary declarations marker
(upper 0) ;; local variables
(lower 0) ) ;; with their initial values
(loop for element in y
DO ;; keyword required
(if (< element 32)
(setf lower (+ lower 1)) ;; affect the value change
(if (> element 212)
(setf upper (+ 1 upper))))) ;; affect the value change
;; CLHS: "Else-form-- The default is nil."
(list lower upper)) ;; NB! More natural order
这段代码实际上是计算超出范围的元素,不应该命名为“
...-inlist
”,这是误导性的。
返回值最好以更自然的递增顺序给出。
代码上的一些注释。
(defun find-inlist (y)
;; upper and lower are not declared, if the Lisp environment is nice, at
;; best you are modifying global variables, which is not a good idea in
;; general. You can introduce new variables with (let ((upper 0) (lower 0))
;; ...) instead. Since you are using LOOP below, you can also start your
;; LOOP using: LOOP WITH UPPER = 0 AND LOWER = 0, which declares local
;; variables too.
(setq upper 0)
(setq lower 0)
;;
(loop
for element in y
;; (if ...) is an expression and produce a value, but what should be done of the value being
;; computed? Unless you instruct the LOOP macro to do something with it,
;; the value will be discarded. Here you have a syntax error because LOOP
;; expects a keyword, like DO, or COLLECT, etc.
(if (< element 32)
;; (+ x y) computes "x + y", but does not update neither x nor y.
;; Maybe you wanted to assign the computed value to lower?
;;
;; (setf lower (+ lower 1))
;;
;; If so, there is a shorthand notation, which is (incf lower)
;;
(+ lower 1)
;; Same here
(if (> elemen 212)
(+ 1 upper)
)))
;; If you use WITH in the LOOP declaration, then UPPER and LOWER won't be
;; visible here, but you can use FINALLY (RETURN (LIST ...)) in the LOOP.
(list upper lower))
还有:
elemen
,这是一个拼写错误(if x y)
更好地写为 (when x y)
(当 then 分支为 unless
时,nil
也是如此。(感谢@tripleee)