我不知道如何使用sb-ext:muffle-conditions
。我想做这样的事情:
(declaim #+sbcl(sb-ext:muffle-conditions sb-kernel:redefinition-warning))
当然,除了我想掩盖"未定义变量"的警告,而不是重新定义。
如果有人知道这是什么参数,或者有sb-ext:muffle-conditions
的文档/各种选项的链接,请分享:)谢谢
我不确定您是否能够具体地抑制这种类型的警告,至少可以通过类名来抑制。通过追踪warn
,我们可以了解SBCL正在做什么。例如,看看在重新定义的情况下会发生什么:
* (trace warn)
(WARN)
* (defun foo () nil)
FOO
* (defun foo () nil)
0: (WARN SB-KERNEL:REDEFINITION-WITH-DEFUN :NAME FOO :NEW-FUNCTION
#<FUNCTION FOO {10041FA989}> :NEW-LOCATION
#S(SB-C:DEFINITION-SOURCE-LOCATION
:NAMESTRING NIL
:TOPLEVEL-FORM-NUMBER NIL
:PLIST NIL))
STYLE-WARNING: redefining COMMON-LISP-USER::FOO in DEFUN
0: WARN returned NIL
FOO
调用warn
时使用类sb-kernel:redefinition-with-defun
和参数作为类指示符,因此发出的警告具有某种特定的类类型。能够根据特定的类别类型进行消音,使消音更容易。
现在,看看在未定义变量的情况下会发生什么:
* (defun foo2 () x)
0: (WARN "undefined ~(~A~): ~S" :VARIABLE X)
; in: DEFUN FOO2
; (BLOCK FOO2 X)
;
; caught WARNING:
; undefined variable: X
0: WARN returned NIL
;
; compilation unit finished
; Undefined variable:
; X
; caught 1 WARNING condition
FOO2
warn
是用一个格式字符串和一些参数调用的,所以发出的警告只是一个simple-warning
。现在,你仍然可以做一些事情来掩盖它,但它有点复杂。
根据SBCL手册第3.1.1节"控制详细性",sb-ext:muffle-conditions
只是使用muffle-warning
重新启动。因为未定义的变量警告只是一个simple-warning
,而且我们可能不想掩盖所有simple-warning
,所以我们需要有点狡猾,使用处理程序绑定指定的处理程序来检查条件。由于我们已经看到了调用warn
的参数,所以我们可以非常具体地了解到什么。我们可以用undefined-variable-warning-p
:识别这些警告
(defun undefined-variable-warning-p (w)
(let ((control (simple-condition-format-control w))
(arguments (simple-condition-format-arguments w)))
(and (= 2 (length arguments))
(eq :variable (first arguments))
(string= control "undefined ~(~A~): ~S"))))
现在,我们可以将编译表单封装在适当的handler-bind
中。例如,让我们看看有和没有处理程序的(compile nil (lambda () x))
:
CL-USER> (compile nil '(lambda () x))
;
; caught WARNING:
; undefined variable: X
;
; compilation unit finished
; Undefined variable:
; X
; caught 1 WARNING condition
#<FUNCTION (LAMBDA ()) {1003AA4F89}>
T
T
CL-USER> (handler-bind
((simple-warning
#'(lambda (w)
(when (undefined-variable-warning-p w)
(invoke-restart 'muffle-warning)))))
(compile nil '(lambda () x)))
#<FUNCTION (LAMBDA ()) {1003B737E9}>
NIL
NIL
我们已经成功地编译了函数并屏蔽了未定义的变量警告。但是,请注意,不能简单地将defun
封装在其中。例如,
CL-USER> (handler-bind
((simple-warning
#'(lambda (w)
(when (undefined-variable-warning-p w)
(invoke-restart 'muffle-warning)))))
(defun some-function () x))
; in: DEFUN SOME-FUNCTION
; (DEFUN SOME-FUNCTION () X)
; --> PROGN EVAL-WHEN SB-IMPL::%DEFUN SB-INT:NAMED-LAMBDA FUNCTION
; ==>
; (BLOCK SOME-FUNCTION X)
;
; caught WARNING:
; undefined variable: X
;
; compilation unit finished
; Undefined variable:
; X
; caught 1 WARNING condition
SOME-FUNCTION
然而,如果你eval
是同一个defun
(但我并不是说你应该这样做),警告就会减弱:
CL-USER> (handler-bind
((simple-warning
#'(lambda (w)
(when (undefined-variable-warning-p w)
(invoke-restart 'muffle-warning)))))
(eval '(defun some-other-function () x)))
SOME-OTHER-FUNCTION
我不确定这到底是为什么,但我希望有人能在评论中详细说明。我怀疑这来自SBCL在REPL上编译表单,这意味着defun
的主体是在整个表单运行之前编译的,因此编译是在处理程序就位之前进行的。