公共Lisp-CCL,为什么在将全局函数传递给本地函数时会发出警告?

公共Lisp-CCL,为什么在将全局函数传递给本地函数时会发出警告?,lisp,common-lisp,ccl,Lisp,Common Lisp,Ccl,我正在学习通用Lisp,使用CCL。 当我在本地使用全局变量时,会收到警告。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 globa

我正在学习通用Lisp,使用CCL。 当我在本地使用全局变量时,会收到警告。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)

快速谷歌搜索表明,在Common Lisp中,它是这样做的:

(defvar *n* 75)

(defun use-global () (write *n*))

(use-global)

请注意,星号按惯例修饰全局名称。

快速谷歌搜索建议在Common Lisp中,它是按如下方式完成的:

(defvar *n* 75)

(defun use-global () (write *n*))

(use-global)

请注意星号按惯例修饰全局名称。

Setf
setq
不引入新变量,而是修改现有变量

要定义类似全局变量的内容,请使用
defvar
defparameter
。按照惯例,它们是以一个开头和结尾的
*
编写的,并且它们会自动声明为全局特殊。这意味着,每当您重新绑定它们时,该绑定对其上方的整个调用堆栈有效,无论您从那里调用什么函数等等


在您的示例中,顶级
setf
没有这样做,因此在编译函数
use global
时,编译器看不到
n
的意思,并发出警告。在正确且惯用的通用Lisp代码中,此警告通常应视为错误,因为它表示拼写错误或打字错误。

Setf
setq
不引入新变量,而是修改现有变量

要定义类似全局变量的内容,请使用
defvar
defparameter
。按照惯例,它们是以一个开头和结尾的
*
编写的,并且它们会自动声明为全局特殊。这意味着,每当您重新绑定它们时,该绑定对其上方的整个调用堆栈有效,无论您从那里调用什么函数等等


在您的示例中,顶级
setf
没有这样做,因此在编译函数
use global
时,编译器看不到
n
的意思,并发出警告。在正确且惯用的通用Lisp代码中,此警告通常应视为错误,因为它表示拼写错误或打字错误。

此警告没有什么价值。该变量由先前的顶级赋值绑定,该赋值在将该变量设置为全局变量时创建绑定。它只是被访问,这很可能是程序员想要的

未绑定变量警告在未看到变量定义时非常有用,因为它捕获变量引用的拼写错误。但是实现应该注意顶级的
setf
setq
,并将其视为一个定义

当变量由顶级的
setf
定义,然后又受
let
约束时,有一个警告是很有用的:

(setf n 42)

(let ((n 43)) (func))
在这里,程序员可能希望
n
是一个特殊变量,但它不是这样定义的
func
将看到
n
的顶级绑定,其中包含42个,而不是词法
n
中包含43个。所以这里有一个很好的理由进行诊断。代码的意图要求通过
defvar
defparameter
声明
n
,或声明特殊

(当然,我们不能在没有看到顶级
n
时警告
(让((n43))…)
,因为这是绝大多数词汇变量的常见情况。)

ANSI Common Lisp中有一点缺陷,因为该部分说只有三种变量:动态变量、词汇变量和常量变量。动态变量是声明为特殊的变量,因此根据这种推理,
setf
不足以创建动态变量。然而,该节明确指出,存在一个全球环境。令人困惑的是,它说它包含具有不确定范围和范围的绑定,并且它包含动态变量。但是,术语表中将“动态变量”定义为在动态环境中具有绑定的变量,将动态环境定义为包含具有“动态范围”的绑定。所以这不可能是全球环境。你知道,3.1.1.1说的那个包含动态变量


无论如何,所有这些ANSI混淆已经造成了这样一种误解,即
setf
setq
无法创建变量,从而支持伪编译器诊断。

该警告没有什么价值。该变量由先前的顶级赋值绑定,该赋值在将该变量设置为全局变量时创建绑定。它只是被访问,这很可能是程序员想要的

未绑定变量警告在未看到变量定义时非常有用,因为它捕获变量引用的拼写错误。但是实现应该注意顶级的
setf
setq
,并将其视为一个定义

当变量由顶级的
setf
定义,然后又受
let
约束时,有一个警告是很有用的:

(setf n 42)

(let ((n 43)) (func))
在这里,程序员可能希望
n
是一个特殊变量,但它不是这样定义的
func
将看到
n
的顶级绑定,其中包含42个,而不是词法
n
中包含43个。所以这里有一个很好的理由进行诊断。代码的意图要求通过
defvar
defparameter
声明
n
,或声明特殊

(当然,我们不能在没有看到顶级
n
时警告
(让((n43))…)
,因为这是绝大多数词汇变量的常见情况。)

ANSI Common Lisp在这方面有一点缺陷