考虑以下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
和2
都替换为change
和(x+3)
在x
。但是,我不明白的是,为什么动态作用域仅用change
取代4
中的x
而取代(x+3)
4
取代DATEADD()
{1}}。
这有点令人困惑,我想知道如何解决这些问题是否有任何诀窍。
答案 0 :(得分:2)
自由变量是在函数中使用但未在函数中定义的变量。在您的示例代码中,唯一的自由变量是函数x
的变量change
:
let change z = z - x
函数change
使用x
但未定义它。
范围界定的本质是确定自由变量引用的变量定义, referent 是什么。在您的示例代码中,它归结为确定x
函数中自由变量change
的引用。
对于静态作用域,每个自由变量都有一个静态指示对象。通过静态地包含代码块向外查看程序文本来确定引用,直到找到绑定(定义)。在OCaml中,变量绑定由函数定义和let
引入。因此,您正在寻找绑定change
的{{1}}最近的封闭区块。最近的x
绑定是x
中的函数参数x
。对于示例调用,它的值为2.
对于动态范围,通过查找在需要值时处于活动状态的嵌套函数调用来确定引用对象。换句话说,您希望在调用链中找到定义名为let proc x =
的变量的最内层函数。如果你假装OCaml有动态范围(它绝对不),那么调用链看起来像这样:
x
调用链中proc => app => change
之外的函数是change
,它定义了一个名为app
的变量。因此,对于示例代码,x
的自由变量x
是指由change
定义的变量x
。在示例中,它具有值app
。
4
中的x
不是自由变量。它由x + 3
定义,并在proc
中使用。对于示例调用,无论使用何种范围,它都具有值2.
对于它的价值,我认为考虑用值替换变量并不是特别有用。最好将它们视为与价值观相关联。
我还想说(虽然我可能不应该)动态范围是疯狂的。在确定正在发生的事情时,额外的灵活性绝对不值得额外的复杂性。不必跟踪函数调用链以确定变量的绑定。 (在我看来。)