使用SETF

时间:2018-01-20 18:58:46

标签: variables common-lisp sbcl setf

船员,

我坚持使用SETF定义变量的其中一种类型。我已升级到新机器(以及新版本的SBCL)并且不让我这样做(当然,我得到了适当的" ==>未定义的变量。 .."错误)

我的问题是,我已经编写了20,000行代码(错误地)用SETF定义我的变量,我不喜欢重写所有代码以获得解释器的前景消化它。

有没有办法可以关闭该错误,以便解释可以继续?

感谢任何帮助。

此致,

-Todd

2 个答案:

答案 0 :(得分:2)

一种选择是设置您的包环境,以便裸符号setf引用my-gross-hack::setf而不是cl:setf。例如,您可以设置如下:

(defpackage #:my-gross-hack
  (:use #:cl)
  (:shadow #:setf))

;;; define your own setf here

(defpackage #:my-project
  (use #:cl)
  (shadowing-import-from #:my-gross-hack #:setf))

;;; proceed to use setf willy-nilly

答案 1 :(得分:1)

您可以处理警告,以便编译终止;在这样做的同时,您可以收集足够的信息来修复您的代码

使用SBCL 1.3.13进行测试

处理警告

setf与未定义的变量一起使用时,我有警告。以下调用调试器,我可以从中调用muffle-warning

(handler-bind ((warning #'invoke-debugger)) 
  (compile nil '(lambda () (setf *shame* :on-you))))

警告类型为SIMPLE-WARNING,其中包含以下访问者:SIMPLE-CONDITION-FORMAT-CONTROL and SIMPLE-CONDITION-FORMAT-ARGUMENTS

(defparameter *setf-declarations* nil)

(defun handle-undefined-variables (condition)
  (when (and (typep condition  'simple-warning)
             (string= (simple-condition-format-control condition)
                      "undefined ~(~A~): ~S"))
    (let* ((arguments (simple-condition-format-arguments condition))
           (variable (and (eq (first arguments) :variable)
                          (second arguments))))
      (when variable
        (proclaim `(special ,variable))
        (push variable *setf-declarations*)
        (invoke-restart 'muffle-warning)))))

将其用作处理程序:

(handler-bind ((warning #'handle-undefined-variables))
  ;; compilation, quickload, asdf ...
  )

上面的处理程序不健壮:错误消息可能在将来的版本中发生变化,代码假定参数遵循给定的模式,...但这只需要工作一次,因为从现在起你将要声明所有的变量

修复您的代码

现在您的代码编译完成,摆脱丑陋。或者至少,添加适当的声明。

(with-open-file (out #P"declarations.lisp" :direction :output)
  (let ((*package* (find-package :cl-user)))
    (format out
            "(in-package :cl-user)~%~%~{(defvar ~(~S~))~%~}"
            *setf-declarations*)))

这会迭代您收集的所有符号,并在单个文件中编写声明。 在我的例子中,它将包含:

(in-package :cl-user)

(defvar *shame*)

尝试在不处理错误的情况下干净地重新编译,方法是在编译过程的早期加载此文件,但是在定义包之后。最后,您可能希望找到时间来移动这些声明来代替触发警告的setf表达式。