Lisp 中的 setq 和 defvar [英] setq and defvar in Lisp

查看:30
本文介绍了Lisp 中的 setq 和 defvar的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看到 Practical Common Lisp 使用 (defvar *db* nil) 用于设置全局变量.用 setq 来达到同样的目的不是可以吗?

I see that the Practical Common Lisp uses (defvar *db* nil) for setting up a global variable. Isn't it OK to use setq for the same purpose?

使用 defvarsetq 的优缺点是什么?

What are the advantages/disadvantages of using defvar vs. setq?

推荐答案

引入变量的方法有多种.

DEFVARDEFPARAMETER 引入全局动态变量.DEFVAR 可选择将其设置为某个值,除非它已被定义.DEFPARAMETER 始终将其设置为提供的值.SETQ 不引入变量.

DEFVAR and DEFPARAMETER introduce global dynamic variables. DEFVAR optionally sets it to some value, unless it is already defined. DEFPARAMETER sets it always to the provided value. SETQ does not introduce a variable.

(defparameter *number-of-processes* 10)

(defvar *world* (make-world))     ; the world is made only once.

请注意,您可能永远不想将 DEFVAR 变量命名为 xystreamlimit, ... 为什么?因为这些变量将被声明为特殊的,并且很难撤消.特殊声明是全局的,变量的所有进一步使用都将使用动态绑定.

Notice that you likely never want to DEFVAR variables with names like x, y, stream, limit, ... Why? Because these variables then would be declared special and its difficult to undo that. The special declaration is global and all further uses of the variable would use dynamic binding.

不好:

(defvar x 10)     ; global special variable X, naming convention violated
(defvar y 20)     ; global special variable Y, naming convention violated

(defun foo ()
  (+ x y))        ; refers to special variables X and y

(defun bar (x y)  ; OOPS!! X and Y are special variables
                  ; even though they are parameters of a function!
  (+ (foo) x y))

(bar 5 7)         ; ->   24

更好:始终在名称中使用 * 标记特殊变量!

BETTER: Always mark special variables with * in their names!

(defvar *x* 10)     ; global special variable *X*
(defvar *y* 20)     ; global special variable *Y*

(defun foo ()
  (+ *x* *y*))      ; refers to special variables X and y

(defun bar (x y)    ; Yep! X and Y are lexical variables
  (+ (foo) x y))

(bar 5 7)           ;  ->   42

局部变量通过DEFUN引入,LAMBDALET, MULTIPLE-VALUE-BIND 和许多其他.

Local variables are introduced with DEFUN, LAMBDA, LET, MULTIPLE-VALUE-BIND and many others.

(defun foo (i-am-a-local-variable)
   (print i-am-a-local-variable))

(let ((i-am-also-a-local-variable 'hehe))
  (print i-am-also-a-local-variable))

现在,默认情况下,上述两种形式的局部变量都是词法的,除非它们被声明为SPECIAL.那么它们将是动态变量.

Now, by default the local variables in above two forms are lexical, unless they are declared SPECIAL. Then they would be dynamic variables.

接下来,还有几种形式可以将变量设置为新值. SET, SETQSETF 等.SETQSETF 可以设置词法变量和特殊(动态)变量.

Next, there are also several forms to set a variable to new values. SET, SETQ, SETF and others. SETQ and SETF can set both lexical and special (dynamic) variables.

可移植代码需要设置已经声明的变量.标准未定义设置未声明变量的确切效果.

It is required for portable code that one sets variables that are already declared. The exact effect of setting a not declared variable is undefined by the standard.

所以,如果你知道你的 Common Lisp 实现是做什么的,你可以使用

So, if you know what your Common Lisp implementation does, you can use

(setq world (make-new-world))

在顶层的 Read-Eval-Print-Loop 中.但是不要在您的代码中使用它,因为效果不可移植.通常 SETQ 会设置变量.但是某些实现也可能会在不知道变量 SPECIAL 时声明它(CMU Common Lisp 默认情况下会这样做).这几乎总是不是人们想要的.如果您知道自己在做什么,请将其用于临时用途,而不是用于代码.

in the Read-Eval-Print-Loop at the toplevel. But don't use it in your code, since the effect is not portable. Typically SETQ will set the variable. But some implementation might also declare the variable SPECIAL when it doesn't know it (CMU Common Lisp does that by default). That's almost always not what one would want. Use it for casual use if you know what you do, but not for code.

这里也一样:

(defun make-shiny-new-world ()
  (setq world (make-world 'shiny)))

首先,这样的变量应该写成*world*(加上周围的*字符),以表明它是一个全局特殊变量.其次,它应该之前已经用 DEFVARDEFPARAMETER 声明过.

First, such variables should be written as *world* (with the surrounding * characters), to make clear that it is a global special variable. Second, it should have been declared with DEFVAR or DEFPARAMETER before.

典型的 Lisp 编译器会抱怨上述变量未声明.由于 Common Lisp 中不存在全局词法变量,编译器必须为动态查找生成代码.一些编译器然后说,好吧,我们假设这是一个动态查找,让我们声明它是特殊 - 因为无论如何我们都是这样假设的.

A typical Lisp compiler will complain that above variable is undeclared. Since global lexical variables don't exist in Common Lisp, the compiler has to generate code for a dynamic lookup. Some compiler then say, okay, we assume that this is a dynamic lookup, let's declare it to be special - since that is what we assume anyway.

这篇关于Lisp 中的 setq 和 defvar的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆