通用Lisp范围(动态vs词汇)

问题描述 投票:10回答:1

编辑:我在第一个答案后更改了示例代码,因为我想出了一个简单的版本,它提出了相同的问题。

我目前正在学习Common Lisp的作用域属性。在我以为自己有了扎实的理解之后,我决定编写一些可以预测其结果的示例,但是显然我错了。我有三个问题,每个问题与下面的示例有关:

示例1:

(defmethod fun1 (x)
  (print x)
  (fun2))

(defmethod fun2 ()
  (print x))

(fun1 5)

输出:

5 
*** - EVAL: variable X has no value

问题:这很有意义。 x是静态范围的,并且fun2在没有显式传递x的情况下无法找到x的值。

示例2:

(defvar x 100)

(defmethod fun1 (x)
  (print x)
  (fun2))

(defmethod fun2 ()
  (print x))

(fun1 5)

输出:

5
5

问题:我不明白为什么fun2突然看到x具有fun1给它的值,而不是100的值...

示例3:

(setf x 100)

(defmethod fun1 (x)
  (print x)
  (fun2))

(defmethod fun2 ()
  (print x))

(fun1 5)

输出:

5
100

问题:由于未声明的变量上调用setf显然是未定义的,因此我应该忽略这些结果吗?这恰好是我在第二个示例中所期望的...

任何见识将不胜感激...

dynamic lisp common-lisp scoping lexical
1个回答
19
投票

使用setf设置未定义变量的效果在ANSI Common Lisp中未定义。

defvar将定义特殊变量。此声明是全局的,并且对let绑定也有影响。这就是按照惯例将这些变量写为*foo*的原因。如果您曾经用x定义了defvar,则将其声明为[[special,并且以后可以通过no声明它为[[lexical

let默认情况下提供局部词法变量。如果变量已经被声明为特殊变量(例如由于defvar),那么它将仅创建一个新的本地动态绑定。

更新

示例1。

    没什么。

  • 示例2

    • x已被声明为特殊。现在,对变量x的所有使用都使用动态绑定。调用函数时,将x绑定到5。动态地。现在,其他函数可以访问此动态绑定并获取该值。
    • 示例3

      这是Common Lisp中的
    • undefined行为。您正在设置一个未声明的变量。然后发生的事情取决于实现。您的实现(大多数操作类似)将x

      符号值设置为100。在fun1中,x受词法约束。在fun2中,求值x检索x的符号值(或可能是动态绑定的值)。

      作为执行(其他操作?)的实现的示例:默认情况下,CMUCL实现还将示例3中的x声明为特殊。设置未定义的变量也将其声明为特殊。

      NOTE

      在符合便携式标准的Common Lisp代码中,全局变量由defvardefparameter定义。两者都声明这些变量是特殊的。现在,这些变量的所有使用都涉及动态绑定。

      记住:

      ((lambda (x) (sin x)) 10)

      基本上与]相同>

      (let ((x 10))
        (sin x))
      

      这意味着let绑定中的变量绑定和函数调用中的变量绑定以相同的方式工作。如果x早些时候被宣布为特殊,则两者都将涉及动态绑定。

      这是在Common Lisp标准中指定的。例如,请参见SPECIAL declaration的说明。
    © www.soinside.com 2019 - 2024. All rights reserved.