公共Lisp-CCL,为什么在将全局函数传递给本地函数时会发出警告?
我正在学习通用Lisp,使用CCL。 当我在本地使用全局变量时,会收到警告。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
(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在这方面有一点缺陷