全体人员,
我是坚持用 SETF 定义变量的类型之一。我已经升级到一台新机器(和一个新版本的 SBCL),它并没有让我侥幸逃脱(当然,我得到了适当的“==> undefined variable...”错误)
我的问题是,我已经编写了 20,000 行代码(错误地)用 SETF 定义我的变量,我不喜欢重写我的所有代码以让解释器消化所有代码的前景。
有没有办法关闭该错误以便解释可以继续?
任何帮助表示赞赏。
真挚地,
-托德
全体人员,
我是坚持用 SETF 定义变量的类型之一。我已经升级到一台新机器(和一个新版本的 SBCL),它并没有让我侥幸逃脱(当然,我得到了适当的“==> undefined variable...”错误)
我的问题是,我已经编写了 20,000 行代码(错误地)用 SETF 定义我的变量,我不喜欢重写我的所有代码以让解释器消化所有代码的前景。
有没有办法关闭该错误以便解释可以继续?
任何帮助表示赞赏。
真挚地,
-托德
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
您可以处理警告,以便编译终止;这样做时,您可以收集足够的信息来修复您的代码。
用 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
和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
触发警告的表达式的位置。