我以为我可以通过Google,SO或者我正在阅读的书籍找到这个,但事实证明这是难以捉摸的.
在我正在学习的实现中,我可以在顶层执行以下操作:
(defvar *foo* 4)
(set 'bar 3)
如果我再调用(describe '*foo*)和(describe 'bar),我得到一个描述说,*foo*是特殊的,bar非特殊(其他细节之中).
是否有一个函数将符号变量作为参数并返回true或false如果它是特殊的?如果是这样,describe可能部分通过调用来实现?
上下文:我正在学习Common Lisp,但是在工作中我有一个类似于Common Lisp的Lisp方言系统,但该describe函数未实现.这里有一些XY事情,但我也试图找到Lisp和CL.
Rai*_*wig 10
许多Common Lisp实现variable-information在一些依赖于系统的包中提供该功能.
在SBCL:
* (require :sb-cltl2)
NIL
* (sb-cltl2:variable-information '*standard-output*)
:SPECIAL
NIL
((TYPE . STREAM))
Run Code Online (Sandbox Code Playgroud)
此功能是作为ANSI CL中包含的其他功能的一部分提出的,但未将其纳入标准.还有很多实现都有它.有关文档,请参阅:https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node102.html
当您在其上创建闭包时,将捕获非特殊变量的环境:
(let ((x 1))
(let ((f (lambda () x)))
(let ((x 2))
(eql 2 (funcall f)))))
;;=> NIL
Run Code Online (Sandbox Code Playgroud)
特殊变量的词汇环境不会:
(defvar *x*) ; *x* is special
(let ((*x* 1))
(let ((f (lambda () *x*)))
(let ((*x* 2))
(eql 2 (funcall f)))))
;;=> T
Run Code Online (Sandbox Code Playgroud)
使用这种方法,您可以轻松定义一个宏,该宏将扩展为像以前一样的代码,可以让您确定符号是否全局声明为特殊:
(defmacro specialp (symbol)
(let ((f (gensym "FUNC-")))
`(let ((,symbol 1))
(let ((,f (lambda () ,symbol)))
(let ((,symbol 2))
(eql 2 (funcall ,f)))))))
(specialp x) ;=> NIL
(specialp *x*) ;=> T
Run Code Online (Sandbox Code Playgroud)
请注意,这不是一个函数,它是一个宏.这意味着使用符号 X和*X*调用specialp的宏函数.这很重要,因为我们必须构造使用这些符号的代码.你不能用一个函数来做这个,因为没有(可移植的)方法来获取符号并创建一个词法环境,它具有一个带有该名称的词法变量和一个引用它的lambda函数.
如果您尝试将其与某些符号一起使用,这也存在一些风险.例如,在SBCL中,如果您尝试将*standard-output*绑定到不是流或流指示符的内容,则会出现错误:
CL-USER> (specialp *standard-output*)
; in: SPECIALP *STANDARD-OUTPUT*
; (LET ((*STANDARD-OUTPUT* 1))
; (LET ((#:FUNC-1038 (LAMBDA # *STANDARD-OUTPUT*)))
; (LET ((*STANDARD-OUTPUT* 2))
; (EQL 2 (FUNCALL #:FUNC-1038)))))
;
; caught WARNING:
; Constant 1 conflicts with its asserted type STREAM.
; See also:
; The SBCL Manual, Node "Handling of Types"
;
; compilation unit finished
; caught 1 WARNING condition
Run Code Online (Sandbox Code Playgroud)