根据我的理解,Common Lisp没有全局词法范围,因此如果要创建全局变量,则必须使用defvar
而不是setq
。我正在尝试创建一个自动执行此操作的宏,即我想写
(= x 1)
无论我在哪里,都能“正常工作”。我想这个宏看起来像
(defmacro = (name value)
`(,(if (is-global) 'defvar 'setf) ,name ,value))
如何撰写is-global
?
答案 0 :(得分:4)
根据我的理解,Common Lisp没有全局词汇范围,
这部分是正确的,但有一些"典型的"解决方法。没有规范的实现,但searching for deflexical可以引导您进行一些实现。
因此,如果您想创建全局变量,则必须使用defvar 而不是setq。(强调添加)
这是不正确的。在大多数情况下,您并非真正创建变量。您将绑定引入环境。最常见的方法是使用 let 或作为函数的参数。 E.g:
(defun foo (bar)
;; in here, there's a variable `bar`
)
(let ((a ...))
;; a is bound in here
这些是词法绑定,除非标识源中变量的符号被声明为特殊,在Common Lisp中它表示它是一个动态范围的变量。您可以执行以下特殊声明:
(defun foo (bar)
(declare (special bar))
;; in here, there's a variable `bar`
)
(let ((a ...))
(declare (special a))
;; a is bound in here
现在,您还可以使用 defparameter 和 defvar 引入全局变量。这些全局将变量声明为特殊变量。
在两个案例中,您可以使用 setq 或 setf 来更新变量的值。也就是说,您可以使用 setq 或 setf 来更新词法变量的值以及特殊变量。所以你可以这样做:
(defparameter *cat* (make-initial-cat))
(let ((cat (some-local-cat)))
(setf *cat* (make-instance 'cat)) ; update global/dynamic
(setf cat (make-instance 'cat)) ; update local/lexical
setf 适用于这两种情况,因此听起来您正在寻找的分配运算符只是 setf 。
听起来你正在尝试解决的问题是你不应该使用 setf / setq 和未声明的变量。确实,这是不确定的行为。所以听起来你正试图让你的赋值操作符自动引入一个变量,如果周围环境中没有变量那么。你不能这样做,至少有两个原因:
答案 1 :(得分:3)
defvar
和defparameter
都会生成具有动态范围的全局特殊变量。 defvar
只会在尚未定义的情况下创建变量。从而。如果你有一个计数器并重新加载你的源代码,如果它是用defvar
定义的,它将不会被重置,但如果用defparameter
定义它将会重新开始。
setf
实际上是setq
的宏,它会改变变量。它不关心变量是全局的,词汇的还是特殊的。
在代码内部定义新的全局变量是一种非常糟糕的做法。你会得到惊喜。动态捕获特殊变量,因此您可以很难调试行为。这就是为什么我们使用*earmuffs*
的命名约定来区分词法变量和特殊变量。
无论如何,如果您只想创建一个全局变量并确保将值设置为所需的值,请使用defparameter
。无论你身在何处,它都会有效。
(defparameter *test* 10) ; ==> *test*
*test* ; ==> 10
重新定义=
是不明智的,因为它是用于检查数字相等的函数。