船员,
我坚持使用SETF定义变量的其中一种类型。我已升级到新机器(以及新版本的SBCL)并且不让我这样做(当然,我得到了适当的" ==>未定义的变量。 .."错误)
我的问题是,我已经编写了20,000行代码(错误地)用SETF定义我的变量,我不喜欢重写所有代码以获得解释器的前景消化它。
有没有办法可以关闭该错误,以便解释可以继续?
感谢任何帮助。
此致,
-Todd
答案 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
表达式。