在 Lisp 中为全局变量赋值

Assigning values to global variables in Lisp

我是 Lisp 的新手,我想了解变量和分配变量的工作原理。我正在尝试检查给定数字是否为 5。如果是,则应该将其更改为 10 并打印出来。如果不是,它只是告诉你它不是 5,但我下面的代码不起作用。

(print "Give me a number")
(setq *x* (read))

(defun check(*x*)
    (if (= *x* 5) (setq *x* 10) (format t "~d is not 5" *x*))
)

check(*x*)
print(*x*)


  • check(*x*)print(*x*) 不是 Lisp 语法。将其替换为 (check *x*)(print *x*)
  • 您的函数使用一些 *x*,但它 不是 您的全局 *x*,而是参数列表中的局部变量 *x* .不要将函数参数命名为与全局变量相同的名称。检查这个例子:
(defparameter a 8)
(defun add (a)
  (setf a (+ a 2))
  (print a))
(add a)
(print a)

返回值为 10,然后是 8。将其与:

进行比较
(defparameter *a* 8)
(defun add (a)
  (setf *a* (+ *a* 2))
  (print *a*))
(add *a*)
(print *a*)

返回值为 10 和 10。

  • 不要使用setfsetq来创建变量,这些函数仅用于设置新值。请改用 defparameter or defvar
  • 此代码为全局变量赋值:
(print "Give me a number")
(defparameter *x* (read *query-io*))
(defun check ()
  (if (= *x* 5)
      (setf *x* 10)
    (format t "~d is not 5" *x*)))
(check)
(print *x*)
  • 您也可以在没有全局变量的情况下完成此任务。
(print "Give me a number")
(defun check (n)
  (if (= n 5)
      (setf n 10) 
    (format t "~d is not 5" n)) 
  (print n))
(check (read *query-io*))

如果我在 SBCL 中用这个定义编译一个文件:

(print "Give me a number")
(setq *x* (read))

(defun check(*x*)
    (if (= *x* 5) (setq *x* 10) (format t "~d is not 5" *x*))
)

有两个警告:

warning: undefined variable: *X*

这位于全局 setq,因为 setq 声明 全局变量。所以编译器不知道任何名为 *x*.

的全局变量

然后,函数内部:

style-warning:
 using the lexical binding of the symbol (*X*), not the
 dynamic binding, even though the name follows
 the usual naming convention (names like *FOO*) for special variables
 --> PROGN SB-IMPL::%DEFUN SB-IMPL::%DEFUN SB-INT:NAMED-LAMBDA
 ==>
   #'(SB-INT:NAMED-LAMBDA AAAB::CHECK
         (*X*)
       (DECLARE (SB-C::TOP-LEVEL-FORM))
       (BLOCK CHECK
         (IF (= *X* 5)
             (SETQ *X* 10)
             (FORMAT T "~d is not 5" *X*))))

这是不言自明的,但这里的绑定是词法的。

但这不是 defun 的 属性,这是因为没有声明名为 *x*.

的特殊变量

如果您改为使用 defvardefparameter,则不会出现警告(例如 (defvar *x* 0))。如果您仅将变量声明为特殊变量,情况也是如此:(declaim (special *x*)),然后再定义绑定它的函数。

在函数内部,假设 *x* 被声明为特殊变量,绑定作为 let,这意味着您可以使用特殊变量作为函数参数。在您的情况下,这并没有太大变化,因为您只使用内部 setq 设置当前绑定(参数隐藏全局绑定),所以实际上这很像词法变量。

但是你可以使用一个特殊的变量来动态地重新绑定一个参数:

(defun foo (*a*) ...)

这等同于:

(defun foo (a)
  (let ((*a* a))
     ...))