C语言在编译期间采用范围绑定(变量引用得到固定地址 - 根本不会改变),这是 静态范围 <的示例/强>
Elisp语言在运行时采用范围绑定(变量指向自己的个人引用堆栈的顶部,let
/ defun
/ ...特殊表单在进入时添加到堆栈顶部从离开的顶部 - 在那个时间捕获已修改的),这是 动态范围 的示例。
词法范围 中使用了哪种类型的绑定?
Common Lisp,Python,R,JavaScript等语言表明它们实现了词法范围。
这些语言的实施使用了哪些技术?
我听说带有功能外观的 环境 。如果我对 - 环境何时创建?
是否可以或通常手动构建和绑定环境以供开发人员使用?像call( bind_env(make_env({buf: [...], len: 5}), myfunc) )
答案 0 :(得分:4)
简而言之,词法作用域在编译时发生(或者更准确地说,在评估函数定义时)。此外,词法范围可以是静态范围:这是ML语言(SML,OCaml,Haskell)的用法。
每个功能都在某些环境中定义。此外,每个函数在封闭环境中创建自己的本地环境嵌套。 顶级环境是所有常见变量,函数(+
,-
,sin
,map
等)和语法(相关的)可以扩展语法的语言,如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
Common Lisp使用词法作用域用于局部变量(由let
形式引入)和动态作用域用于全局变量(它们也称为特殊;可以声明局部变量特殊,但很少使用),defvar
和defparameter
定义。为了将它们与词法范围的变量区分开来,它们的名字通常都有&#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,不能这样做(除非使用某种形式的反射)。但这与他们使用什么样的范围有很弱的联系。