我试着理解Scheme中的引用现象是如何工作的。特别是,我想了解何时绑定引用术语的自由变量。
例如,当我写
时(define q 'a)
(define a 42)
(eval q)
它返回42.因此我推断出绑定时间是在运行时。但在这种情况下,为什么这段代码失败
(let ((q 'a))
(let ((a 42))
(eval q)
)
)
并返回
unbound variable: a
有人可以解释一下引用术语的约束时间模型是什么(例如,与MetaOCaml相当吗?(我不这么认为))和define和let之间的区别?
答案 0 :(得分:2)
Scheme具有词法范围规则,而不是动态绑定规则。
您的顶级define
定义的行为就像在顶级词汇环境中创建绑定一样。
第二个代码片段实际上创建了两个词法环境,一个嵌套在另一个环境中。那么({em> not“when”)q
被绑定的地方,a
仍未绑定。但真正的问题是,eval
使用了哪种环境?
您的实现表现得好像它使用定义环境或顶级环境,但肯定不是当前的词法环境,用于评估符号 'a
,这是值q
变量。 变量 q
具有明确的绑定词汇环境,由其let
表单创建 - 但符号 'a
的位置在哪里s绑定驻留?我们怎么知道?
详细信息应该在文档中。
答案 1 :(得分:1)
首先,引用符号与字符串一样多,变量与字符串相同,字符序列与C语言语言(如Javascript)中的变量相同。他们没有任何共同点,因为他们生活在不同的世界。
eval
不知道词汇变量,只知道全局变量。它知道要评估的结构中的词法变量。例如。
(eval '(let ((tmp (list q q)))
tmp))
q
需要是全局的,但tmp
是一个词法变量。
标准方案,又名R6RS,采用第二个参数,您可以选择哪些库应该可用。这些仍被认为是全球性的。
变量在运行时绑定。只要此优化不会破坏报告,实现就可以自由优化和不断折叠。
eval
是一个强大的程序,除非它是解决问题最明智的方法,否则不应该使用它。在我17年的职业生涯中,我已经在生产代码中看到了两次,我认为这一次太多了。