Scope 静态作用域与动态作用域

Scope 静态作用域与动态作用域,scope,ocaml,Scope,Ocaml,考虑以下Ocaml代码: let app f y = let x = 4 in (f y)+1 ;; let proc x = let change z = z-x in app change (x+3) ;; (proc 2) 据我所知,静态作用域使用代码的结构来确定变量的值,因此在本例中,x在change和(x+3)中都被2替换。然而,我不明白的是,为什么动态作用域只将change中的x替换为4,而不是(x+3)中的x替换为4 这有点让人困惑,我想知道是否有什么诀窍可以解决这些问题。自由

考虑以下Ocaml代码:

let app f y = let x = 4 in (f y)+1 ;;
let proc x = let change z = z-x in app change (x+3) ;; 
(proc 2)
据我所知,静态作用域使用代码的结构来确定变量的值,因此在本例中,
x
change
(x+3)
中都被
2
替换。然而,我不明白的是,为什么动态作用域只将
change
中的
x
替换为
4
,而不是
(x+3)
中的
x
替换为
4


这有点让人困惑,我想知道是否有什么诀窍可以解决这些问题。

自由变量是一个函数中使用但函数中未定义的变量。在示例代码中,唯一的自由变量是函数
change
的变量
x

let change z = z - x
函数
change
使用
x
,但不定义它

范围界定的本质是确定自由变量所引用的变量定义,以及它的引用对象。在示例代码中,它归结为在
change
函数中确定自由变量
x
的引用对象

对于静态范围,每个自由变量都有一个静态引用。通过在程序文本中向外查看静态包含的代码块,直到找到绑定(定义)为止,就可以确定引用对象。在OCaml中,变量绑定由函数定义和
let
引入。因此,您正在查找绑定
x
的最近的
change
封闭块。
x
的最近绑定是
let proc x=
中的函数参数
x
。对于示例调用,其值为2

对于动态作用域,通过查找在需要值时处于活动状态的嵌套函数调用来确定引用对象。换句话说,您希望在调用链中找到最里面的函数,该函数定义了一个名为
x
的变量。如果您假装OCaml具有动态范围(它肯定没有),调用链如下所示:

proc => app => change
调用链中
change
外部的函数是
app
,它定义了一个名为
x
的变量。因此,对于示例代码,
change
的自由变量
x
指由
app
定义的变量
x
。在本例中,其值为
4

x+3
中的
x
不是自由变量。它由
proc
定义,并在
proc
中使用。对于示例调用,无论使用什么作用域,它都具有值2

不管它值多少钱,我不认为用值替换变量特别有用。最好将它们视为受价值观约束

我还想说(尽管我可能不应该说)动态范围界定是疯狂的。这种额外的灵活性绝对不值得为弄清发生了什么而付出额外的复杂性。不必通过跟踪函数调用链来确定变量的绑定。(在我看来。)