【问题标题】:What's difference between defvar, defparameter, setf and setqdefvar、defparameter、setf 和 setq 有什么区别
【发布时间】:2012-02-14 05:04:47
【问题描述】:

我找到了Similar question

但我不太明白那个解释。

所以我尝试使用以下示例运行 clisp:

  [1]> (defvar a 5)
  A
  [2]> (+ a 1)
  6
  [3]> (defparameter b 5)
  B
  [4]> (+ b 1)
  6
  [5]> (setf c 5)
  5
  [6]> (+ c 1)
  6
  [7]> (setq d 5)
  5
  [8]> (+ d 1)
  6
  [9]> (let ((a 500)) (+ a 1))
  501
  [10]> (let ((b 500)) (+ b 1))
  501
  [11]> (let ((c 500)) (+ c 1))
  501
  [12]> (let ((d 500)) (+ d 1))
  501
  [13]> 

我发现的完全一样。

我不知道他们有什么不同?

【问题讨论】:

    标签: lisp common-lisp clisp


    【解决方案1】:

    DEFPARAMETER 总是分配一个值。所以:

    [1]> (defparameter a 1)
    A
    [2]> (defparameter a 2)
    A
    [3]> a
    2
    

    DEFVAR 只执行一次,所以:

    [4]> (defvar b 1)
    B
    [5]> (defvar b 2)
    B
    [6]> b
    1
    

    SETF 是一个在内部使用SETQ 的宏,但有更多的可能性。在某种程度上,它是一个更通用的赋值运算符。例如。使用SETF 你可以这样做:

    [19]> (defparameter c (list 1 2 3))
    [21]> (setf (car c) 42)                                              
    42
    [22]> c
    (42 2 3)
    

    但你不能用 SETQ 做到这一点:

    [23]> (setq (car c) 42)                                              
    *** - SETQ: (CAR C) is not a symbol
    The following restarts are available:
    USE-VALUE      :R1      Input a value to be used instead.
    ABORT          :R2      Abort main loop
    Break 1 [24]> abort
    

    【讨论】:

    • 如果我用defvar定义的变量,我可以通过defparameter改变值吗?是正确的方法吗?或者只有defparameter中定义的变量可以被defparameter改变?谢谢~
    • 正确的方法是在文件中使用 DEFVAR 和 DEFPARAMETER 进行值初始化,使用其中之一在监听器中声明动态变量,并始终使用 SETF 更改非顶层代码中的值。然后 DEFVAR 和 DEFPARAMETER 之间的区别变为“我是否要在每次加载此文件时重置值”(使用 defparamete),“或不?” (使用 defvar)。
    【解决方案2】:

    defvardefparameter 都将变量声明为“动态范围变量”。此外,defparameter 将始终将变量的值设置为您作为第二个参数传入的值。这与defvar 不同,它只会设置之前没有设置过的变量的值。

    在全局词法范围内使用setfsetq 定义变量是未定义的。有些实现会为您创建一个动态范围的变量,有些则不会。第一次执行此操作时,您可能会看到诊断消息。

    要了解词法范围变量和动态范围变量之间的区别,请尝试以下代码 sn-p:

    * (defvar *a* 1)
    
    *A*
    * (let ((*a* 5)) (defun demo-a () *a*))
    
    DEMO-A
    * (let ((b 5)) (defun demo-b () b))
    
    DEMO-B
    * (let ((*a* 100)) (demo-a))
    
    100
    * (let ((b 100)) (demo-b))
    
    5
    

    这里我们创建了一个动态范围的变量和一个返回值的函数(定义在一个绑定中,在函数创建期间它具有不同的值,这不是必需的,只是为了看起来类似于 b 上的词法闭包)。然后我们定义一个新变量并定义一个函数返回它的值。

    之后,我们调用这两个函数,在闭包中将一个值绑定到一个同名变量。在动态范围的情况下,它是同一个变量。在词法闭包情况 (b) 中,它们只是具有相同的名称,但不是同一个变量,因为它们是在两个不同的词法闭包中定义的。

    至于setfsetq 之间的区别,请尝试始终使用setf(我想不出任何(setq blah blahblah) 可以工作而(setf blah blahblah) 不会做同样事情的例子)。

    【讨论】:

    • 现在我知道 defvar 和 defparameter 的区别了。但是什么时候我们应该使用 setf 或 setq 呢?谢谢~
    • @sam:使用defvardefparameterlet 引入新变量。使用setfsetq 改变现有变量。使用它们来引入新变量是未定义的行为。
    • 最后一个例子 (let ((b 100)) (demo-b)) 也给了我 100,而不是如图所示的 5
    • @AndreasRöhler 如果是这样,您之前可能已经完成了顶级 (setq b...),这将导致多个 lisp 环境将变量转换为动态范围。如果您在新启动的 Common Lisp 中尝试它会发生什么?
    • @Vatine Ahh,抱歉,在 Emacs Lisp 中是动态范围的。
    猜你喜欢
    • 2010-10-26
    • 2011-04-20
    • 1970-01-01
    • 2010-11-01
    • 2013-08-12
    • 2013-10-04
    • 2012-12-28
    • 2019-04-09
    相关资源
    最近更新 更多