何时进行词法范围绑定 - 在运行时或编译时?

时间:2016-02-15 00:03:21

标签: language-features lexical-scope dynamic-scope

C语言在编译期间采用范围绑定(变量引用得到固定地址 - 根本不会改变),这是 静态范围 <的示例/强>

Elisp语言在运行时采用范围绑定(变量指向自己的个人引用堆栈的顶部,let / defun / ...特殊表单在进入时添加到堆栈顶部从离开的顶部 - 在那个时间捕获已修改的),这是 动态范围 的示例。

词法范围 中使用了哪种类型的绑定?

Common Lisp,Python,R,JavaScript等语言表明它们实现了词法范围。

这些语言的实施使用了哪些技术?

我听说带有功能外观的 环境 。如果我对 - 环境何时创建?

是否可以或通常手动构建和绑定环境以供开发人员使用?像call( bind_env(make_env({buf: [...], len: 5}), myfunc) )

这样的东西

1 个答案:

答案 0 :(得分:4)

简而言之,词法作用域在编译时发生(或者更准确地说,在评估函数定义时)。此外,词法范围可以是静态范围:这是ML语言(SML,OCaml,Haskell)的用法。

环境

每个功能都在某些环境中定义。此外,每个函数在封闭环境中创建自己的本地环境嵌套顶级环境是所有常见变量,函数(+-sinmap等)和语法(相关的)可以扩展语法的语言,如Common Lisp,Scheme,Clojure)。

每个函数创建自己的本地环境嵌套在封闭环境中(例如,顶级或其他函数)。函数参数和所有局部变量都存在于此环境中。如果函数引用了一个未在本地环境中定义的变量或函数(在此环境中称为 free ),则可以在函数定义的封闭环境中找到(或者在封闭环境的封闭环境中更高)它没有在那里找到等等)。这与动态范围不同,其中值将在调用函数的环境中找到。

我将使用Scheme来说明这一点:

y在此定义中是免费的

(define (foo x)
    (+ x y))

以下是顶级环境中定义的y

(define y 1)

介绍本地&#39; y,但foo将使用y来定义封闭(顶级)环境。因此,结果是2而不是11。

(let ((y 10))
     (foo 1))
 => 2

您还可以使用包含它的本地环境定义函数(或Scheme的术语中的过程):

 (define bar
     (let ((y 100))
          (lambda (x) (+ x y))))

(bar 1)
=> 101

此处将过程值bar定义为过程。变量y在过程体中再次免费。但是封闭环境是由let形式创建的,其中y被定义为100.因此,当调用bar时,它是y的值,它被取出并且不是顶级(在动态作用域语言中它会返回2)。

回答你的上一个问题,可以手动创建自己的环境,但这样做太多了,可能效率不高。实现语言时(例如,Scheme解释器),这正是语言开发人员正在做的事情。

环境的良好解释见SICP, Chapter 3

其他评论

AFAIK,来自Emacs 23,ELisp正在使用词法作用域和动态作用域(类似于Common Lisp,见下文)。

Common Lisp使用词法作用域用于局部变量(由let形式引入)和动态作用域用于全局变量(它们也称为特殊;可以声明局部变量特殊,但很少使用),defvardefparameter定义。为了将它们与词法范围的变量区分开来,它们的名字通常都有&#34;耳罩&#34;,例如*standard-input*。顶级函数在CL中也很特殊,这可能相当危险:可以通过隐藏顶级函数在不知不觉中改变行为。这就是为什么CL标准指定标准库函数的锁定以防止它们重新定义。

相比之下,

Scheme总是使用词法范围。但是,动态作用域有时很有用(Richard Stallman makes a good point on it)。为了解决这个问题,许多Scheme实现引入了所谓的参数(使用词法作用域实现)。

Common Lisp,Scheme,Clojure,Python等语言保持对变量的动态引用:您可以从字符串构造变量名称(在Lisp的术语中实现符号)和找到它的价值。更多静态语言,如C,OCaml或Haskell,不能这样做(除非使用某种形式的反射)。但这与他们使用什么样的范围有很弱的联系。