1

我试图了解 Scheme 中的引用现象是如何工作的。特别是,我想了解引用术语的自由变量何时绑定。

例如,当我写

(define q 'a)
(define a 42)
(eval q)

它返回 42。因此我推断绑定时间是在运行时。但是在这种情况下,为什么这段代码会失败

(let ((q 'a))
  (let ((a 42))
    (eval q)
  )
)

并返回

unbound variable:  a

有人可以解释一下什么是引用术语的绑定时间模型(例如可以与 MetaOCaml 相媲美吗?(我不这么认为))以及定义和让之间的区别?

4

2 回答 2

2

Scheme 具有词汇范围规则,而不是动态绑定规则。

您的顶级define定义的行为就像在顶级词汇环境中创建绑定一样。

第二个代码片段实际上创建了两个词法环境,一个嵌套在另一个内部。所以哪里(不是“何时”q被绑定,a仍然是未绑定的。但真正的问题是,使用哪个环境eval

您的实现表现得好像它使用定义环境或顶级环境,但肯定不是当前词法环境来评估符号 'a,这是q变量的值。变量 有一个清晰的q绑定词法环境,由它的let形式创建——但是symbol 'a的绑定在哪里呢?我们怎么知道?

详细信息应在文档中。

于 2016-05-03T17:35:21.970 回答
1

首先,带引号的符号与具有相同字符序列的字符串一样多的变量与 C 语法语言(如 Javascript)中的变量一样多。他们没有任何共同点,因为他们生活在不同的世界。

eval不知道词法变量,只知道全局变量。它知道要评估的结构中的词法变量。例如。

(eval '(let ((tmp (list q q))) 
          tmp)) 

q需要是全局的,但是tmp是一个词法变量。

标准方案,又名 R6RS,采用第二个参数,您可以在其中选择应该可用的库。这些仍然被认为是全球性的。

变量在运行时绑定。只要这种优化不破坏报告,实现就可以自由优化和不断折叠。

eval是一个强大的程序,除非它是解决问题的最明智的方法,否则永远不应该使用它。在我 17 年的职业生涯中,我在生产代码中见过两次,我认为这一次太多了。

于 2016-05-03T17:43:52.527 回答