我正在使用CCL学习Common Lisp。 我在本地使用全局变量时收到警告。为什么CCL提供此功能?这样做的目的是什么?
(setf n 75)
;;;This function works, but gets a warning about
;;;n being an undeclared free variable.
(defun use-global ()
(write n)
)
;;;This function works without warnings.
(defun global-to-local (x)
(write x)
)
(use-global)
(global-to-local n)
答案 0 :(得分:3)
Setf
和setq
不会引入新变量,它们会修改现有变量。
为了定义类似全局变量的内容,请使用defvar
或defparameter
。通常,它们以开头和结尾的*
开头,并且会自动声明为 global special 。这意味着,只要您重新绑定它们,该绑定将对其上方的整个调用堆栈有效,无论您从那里调用什么功能,等等。
在您的示例中,顶级setf
并没有这样做,因此在编译函数use-global
时,编译器不会看到n
的含义,并发出警告。在正确且惯用的Common Lisp代码中,通常应将此警告视为错误,因为它表示拼写错误或错字。
答案 1 :(得分:2)
该警告几乎没有价值。该变量受先前的顶级分配约束,该顶级分配在global environment中创建绑定,使该变量成为全局变量。它只是被访问,这很可能是程序员想要的。
当未看到变量定义时,未绑定变量警告非常有价值,因为它会捕获变量引用的拼写错误。但是,实现应注意顶层setf
或setq
并将其视为定义。
当变量由顶级setf
定义,然后又受let
约束时,发出警告是很有用的:
(setf n 42)
(let ((n 43)) (func))
在这里,程序员似乎期望n
是一个特殊变量,但并不是那样定义的。 func
会看到n
的顶级绑定,该绑定包含42,而不是词汇表n
的43绑定。因此,这里很有必要进行诊断。代码的目的是要求n
已通过defvar
或defparameter
声明,或被宣布为特殊。
(当然,在没有顶级(let ((n 43)) ...)
的情况下,我们无法警告n
,因为这是绝大多数词法变量的常见情况。)
在ANSI Common Lisp中有一个缺陷,即 3.1.2.1.1 Symbols as Forms 部分说只有三种变量:动态,词法和常量。动态变量是被声明为特殊变量,因此根据这种推理,setf
不足以创建动态变量。但是,第3.1.1.1节明确指出存在全球环境。令人困惑的是,它说它包含具有不确定范围和范围的绑定,并且它包含动态变量。但是,然后在词汇表中将“动态变量”定义为在动态环境中具有绑定的变量,而将动态环境定义为包含具有“动态范围”的绑定。所以那不可能是全球环境。您知道3.1.1.1所说的包含动态变量!
无论如何,所有这些ANSI混淆都造成了误解,认为setf
或setq
无法创建变量,这为伪造的编译器诊断提供了支持。
答案 2 :(得分:0)
在Google Lisp中快速搜索意味着它是通过以下方式完成的:
(defvar *n* 75)
(defun use-global () (write *n*))
(use-global)
请注意按约定装饰全局名称的星号。