Common Lisp 中的 If 循环问题

问题描述 投票:0回答:2

我在使用 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))))
loops if-statement lisp common-lisp
2个回答
1
投票

经过最少编辑的代码的更正形式是:

(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
”,这是误导性的。

返回值最好以更自然的递增顺序给出。


1
投票

代码上的一些注释。

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

© www.soinside.com 2019 - 2024. All rights reserved.