Scope 静态作用域与动态作用域
考虑以下Ocaml代码: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 这有点让人困惑,我想知道是否有什么诀窍可以解决这些问题。自由
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
不管它值多少钱,我不认为用值替换变量特别有用。最好将它们视为受价值观约束
我还想说(尽管我可能不应该说)动态范围界定是疯狂的。这种额外的灵活性绝对不值得为弄清发生了什么而付出额外的复杂性。不必通过跟踪函数调用链来确定变量的绑定。(在我看来。)