OCaml中嵌套`let .. in ..`的评估范围/顺序

All*_*ang 3 evaluation ocaml functional-programming let

我在这里遇到一些问题,我不是百分之百理解:

let x = 1 in let x = x+2 in let x = x+3 in x

我知道这个表达式的结果是6,但只是想确定计算这个表达式的顺序; 首先计算哪部分?

win*_*zki 10

您询问了表达式中评估的顺序let x=1 in let x=x+2 in ....订单是"从左到右"!当你有一个链时let a=b in let c=d in ...,评估的顺序总是从左到右.

但是,在您的示例中有一个令人困惑的部分:您在每个构造中使用相同的变量名称.这很令人困惑,因为你看到了类似的东西,这看起来像是在"重新定义" 或"改变"的价值.但是在OCAML中实际上没有"改变""x"!正如上面已经指出的,这里发生的是每次引入一个新变量,所以你的例子完全等同于xletlet x=x+1xx

 let x = 1 in let y = x+2 in let z = y+3 in z;;
Run Code Online (Sandbox Code Playgroud)

请注意,此处评估顺序也是从左到右.(它总是由左到右的每一个链let的构建.)在你原来的问题,你选择了把所有这些新的变量"X",而不是x,yz.这让大多数人感到困惑.最好避免这种编码风格.

但是我们如何检查我们是否正确地重命名了变量?为什么"让x = 1 in let y = x + 2"而不是"让x = 1 in let x = y + 2"?这个x=x+2生意很混乱!那么,还有另一种理解评估的方法let x=aaa in bbb.构造

  let x=aaa in bbb
Run Code Online (Sandbox Code Playgroud)

可以始终替换为应用的以下闭包aaa,

  (fun x -> bbb) aaa
Run Code Online (Sandbox Code Playgroud)

一旦你以这种方式重写它,你可以很容易地看到两件事:首先,OCAML不会在闭包内评估"bbb",直到评估"aaa".(因此,let x=aaa in bbb通过首先评估aaa然后bbb,即"从左到右"来评估收益.)其次,变量"x"被限制在闭包的主体中,因此"x"不可见在表达"aaa"中.因此,如果"aaa"包含一个名为"x"的变量,那么它之前必须已经定义了一些值,并且它与闭包内的"x"无关.为清楚起见,最好用不同的名称调用此变量.

在你的例子中:

 let x=1 in let x=x+2 in let x=x+3 in x
Run Code Online (Sandbox Code Playgroud)

被重写为

 (fun x -> let x=x+2 in let x=x+3 in x) 1
Run Code Online (Sandbox Code Playgroud)

然后内部let结构也被重写:

 (fun x -> (fun x -> let x=x+3 in x) x+2 ) 1
 (fun x -> (fun x -> (fun x-> x) x+3) x+2 ) 1
Run Code Online (Sandbox Code Playgroud)

现在让我们重命名每个函数内部函数的参数,我们总是可以在不改变代码含义的情况下进行:

 (fun x -> (fun y -> (fun z -> z) y+3) x+2 ) 1
Run Code Online (Sandbox Code Playgroud)

这是一样的

 let x=1 in let y=x+2 in let z=y+3 in z
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您可以验证是否已正确重命名变量.