【问题标题】:In Lisp, how do I fix "Warning: Assumed Special?"在 Lisp 中,如何修复“警告:假定为特殊?”
【发布时间】:2010-10-05 04:35:02
【问题描述】:

在此文件中,我收到 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)

我没有收到任何错误,并且这些功能似乎工作正常。那么为什么会这样说呢?我该如何解决?

【问题讨论】:

    标签: function lisp warnings common-lisp


    【解决方案1】:

    任何未定义的变量都可以被认为是特殊的。另一种解释也没有真正的意义。

    你可以

    • 使用 DEFVAR 或 DEFPARAMETER 将变量作为全局特殊变量引入

    • 使用 DEFUN、LAMBDA、FLET、LABELS、LET、LET* 或其他方法将变量作为局部词法变量引入

    • 将变量声明为特殊变量或将变量引用声明为特殊变量。通常这不是人们想要的。

    无论如何,SETQ 没有定义或声明变量。它所做的只是将现有变量设置为某个值。

    避免在代码中使用 SETQ 设置未定义/声明的变量。它的确切结果在 ANSI Common Lisp 标准中没有定义。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

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

        defvar 用于全局变量,将let 构造用于局部变量。

        【讨论】:

        • 并不是不应该定义一个变量。那是不确定您是否要定义变量。如果你是 (defvar checkarray) 然后是 (setq checkarary (make-array 9)),它会很乐意按照你的要求去做。但是设置了警告,setq 会发出警告。您也可以随时禁用警告。
        猜你喜欢
        • 1970-01-01
        • 2022-01-02
        • 2021-05-11
        • 2018-05-10
        • 2019-08-08
        • 2020-11-28
        • 2017-10-25
        • 2017-07-03
        • 1970-01-01
        相关资源
        最近更新 更多