Lisq范围问题与setq?

时间:2016-02-11 04:18:59

标签: scope lisp

我是lisp的菜鸟,只用了两个星期左右......

我有一些用setq声明的全局变量: (setq myvar '(WHATEVER))

和一个应该修改我告诉它的变量的函数:

(defun MYFUN (varname)
  (setq varname '(POOP))
)

但是当我拨打电话时:(MYFUN 'myvar) 并检查myvar的值,现在它仍然是(WHATEVER)如何在MYFUN中进行更改?

3 个答案:

答案 0 :(得分:5)

没有“使用setq声明全局变量”,只有“使用setq设置变量的值”,如果你在顶级词汇环境中这样做,结果是有趣的 - 定义

如果您查看变量varname包含的内容,则可能是列表(poop)

此外,setq末尾的“q”实际上意味着“引用”(即setq特殊形式不会评估第一个(以及第三个和第五个......)参数,但将在第二个(以及第四个和第六个......)中这样做。

从历史上看,这是一种方便,(set (quote var) value)不如(setq var value)方便。但是,(set var value)(setf (symbol-value var) value)具有完全相同的效果,您应该使用它。

答案 1 :(得分:4)

您正在设置局部变量varname的值,而不是其包含名称的全局变量。要做你想做的事,你需要使用symbol-value访问器间接通过它来获取全局值的变量。

(defun myfun (varname) 
  (setf (symbol-value varname) '(poop)))

答案 2 :(得分:1)

编辑:首先没有注意到这一点:

您在函数体的范围内都有本地varname和全局varname。本地名称会影响全局名称。因此,如果您将本地名称更改为var,它应该按您编写的方式工作(在SBCL 1.2.13中检查)。但请考虑以下风格修正:

  1. 对于全局变量,请在名称周围使用耳罩*,因此它应为*myvar*。全局变量特殊(有一种方法可以使它们正常,但它不一定是个好主意)。特殊变量具有动态范围,与正常变量的词法范围形成对比。
  2. 必须使用defvardefparameter声明变量。您可以使用setq,但编译器会抱怨该变量未定义。此外,使用setq变量也不会特殊。
  3. 如果变量*myvar*在函数体内显得特殊,则需要在函数定义之前声明它(使用defvardefparameter),或者它需要是使用(declare (special *myvar*))在函数正文中声明为特殊,然后使用defvardefparameter声明。
  4. 以下是声明和相应输出的可能组合的代码:

    ;; This is a model solution:
    (defvar *myvar* 'a)
    *MYVAR*
    
    (defun foo (var)
      (setq *myvar* var))
    
    (foo 'b)
    *myvar*
    B
    
    ;; Not using DEFVAR or DEFPARAMETER
    (setq myvar 'a)
    A
    
    (defun bar (var)
      (setq myvar var))
    ;; The value of the global MYVAR is still changed
    (bar 'b)
    myvar
    B
    (defun show-myvar ()
      myvar)
    ;; But MYVAR is not special
    (let ((myvar 'z))
      (show-myvar))
    B
    
    ;; Also can assign value to undeclared variable
    (defun bar2 (var)
      (setq myvar-1 var))
    BAR2
    
    (setq myvar-1 'a)
    A
    ;; And it works
    (bar2 'b)
    myvar-1
    B
    
    ;; Finally: show special undeclared (yet) variable
    (defun show-special ()
      (declare (special *special-var*))
      *special-var*)
    
    (defvar *special-var* 'a)
    *SPECIAL-VAR*
    
    (let ((*special-var* 'z))
      (show-special))
    Z
    
    ;; The same but with SETQ: variable is still not special
    (defun show-special-setq ()
      (declare (special *special-var-setq*))
      *special-var-setq*)
    
    (setq *special-var-setq* 'a)
    A
    (let ((*special-var-setq* 'z))
      (show-special-setq))
    A