在Lisp中,我如何解决“Warning: Assumed Special”的问题?

4
在这个文件中,我收到了9个“假定特殊”的警告。它们分别是:
;;;*** Warning in CHECK-ROW: CHECKARRAY assumed special in SETQ
;;;*** Warning in CHECK-ROW: RESULT assumed special in SETQ
;;;*** Warning in CHECK-ROW: CHECKARRAY assumed special
;;;*** Warning in CHECK-ROW: CHECKARRAY assumed special
;;;*** Warning in CHECK-ROW: CHECKARRAY assumed special
;;;*** Warning in CHECK-ROW: CHECKARRAY assumed special
;;;*** Warning in CHECK-ROW: CHECKARRAY assumed special
;;;*** Warning in CHECK-ROW: RESULT assumed special in SETQ
;;;*** Warning in CHECK-ROW: RESULT assumed special

整个文件只有两个函数 -

(defun get-element (x y board)
 (nth y (nth x board)))

(defun check-row (row board)
 (setq checkarray (make-array 9))
 (setq result T)
 (fill checkarray 0)
 (loop for i upto 8 do
  (setf (aref checkarray (- (get-element row i board) 1))
        (+  (aref checkarray (- (get-element row i board) 1)) 1))
 )
 (loop for i upto 8 do
  (if (or (= (aref checkarray i) 0) (> (aref checkarray i) 1))
      (setq result nil) ())
 )
 result)

我没有收到任何错误提示,而且函数似乎都能正常运作。那为什么会显示这个信息呢?该如何修复它?

3个回答

8

Rainer Joswig的回答通常是正确的。在您的情况下,我没有看到这些变量需要成为全局变量的必要性,所以最好的方法是使用let将它们限制在函数体内部:

(defun check-row (row board)
  (let ((checkarray (make-array 9)) (result t))
    (fill checkarray 0)
    (loop for i upto 8 do
         (setf (aref checkarray (- (get-element row i board) 1))
               (+  (aref checkarray (- (get-element row i board) 1)) 1)))
    (loop for i upto 8 do
         (if (or (= (aref checkarray i) 0) (> (aref checkarray i) 1))
             (setq result nil) ()))
    result))

编辑:另外,由于您只是将1添加到一个位置,因此您可以使用incf代替那个冗长的setf:

(defun check-row (row board)
  (let ((checkarray (make-array 9)) (result t))
    (fill checkarray 0)
    (loop for i upto 8 do
         (incf (aref checkarray (- (get-element row i board) 1))))
    (loop for i upto 8 do
         (if (or (= (aref checkarray i) 0) (> (aref checkarray i) 1))
             (setq result nil) ()))
    result))

8
任何未定义的变量都可以被认为是特殊的。另一种解释也没有什么意义。
您可以通过使用DEFVAR或DEFPARAMETER将变量引入为全局特殊变量,
或者使用DEFUN、LAMBDA、FLET、LABELS、LET、LET*或其他方法将变量引入为本地词法变量,
或者将变量声明为特殊变量或将变量引用声明为特殊变量。通常这不是人们想要的。
无论如何,SETQ不定义或声明变量。它所做的只是将现有的变量设置为某个值。
在代码中避免使用SETQ设置未定义/已声明的变量。其确切后果在ANSI Common Lisp标准中未定义。

1

区别在于setq严格来说不应该用于定义变量(我不确定为什么,因为它确实定义了一个变量)。

对于全局变量,请使用defvar,对于局部变量,请使用let结构。


3
并不是说不允许定义一个变量,而是不确定您是否想要定义一个变量。如果您使用(defvar checkarray),然后稍后使用(setq checkarray (make-array 9)),它会愉快地执行您的请求。但是如果设置了警告,则setq语句将发出警告。您也可以随时禁用警告。 - Will Hartung

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接