In Lisp, how do I fix "Warning: Assumed Special?"
In this file I get 9 warnings of "assumed special". They are
;;;*** 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
The whole file is just two functions -
(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)
I don't get any errors and the functions seem to work fine. So why does it say this? And how can I fix it?
Any variable not defined may be assumed to be special. Another interpretation also does not really make sense.
You may either
- introduce your variables as global special variables using DEFVAR or DEFPARAMETER
or
- introduce your variables as local lexical variables using DEFUN, LAMBDA, FLET, LABELS, LET, LET* or others
or
- declare your variables as special or declare the variable reference as special. Usually this is not what one wants.
Anyway, SETQ does not define a or declare a variable. All it does is that it sets an existing variable to some value.
Avoid setting undefined/declared variables with SETQ in code. Its exact consequences are undefined in the ANSI Common Lisp standard.
Rainer Joswig's answer is correct in general. In your case, I don't see any need for these variables to be global, so the best thing to do is use let
to make them local to the body of your function:
(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))
Edit: Also, since you're just adding 1 to a place, you can use incf instead of that long 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))
The difference is that setq is not, strictly speaking, supposed to be used to define a variable (I am not exactly sure why, since it does define a variable).
Use defvar
for globals and the let
construct for locals.
精彩评论