3

ここには、100% 理解できない小さな問題があります。

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

この式の結果が 6 であることはわかっていますが、この式の計算順序を確認したいだけです。どの部分が最初に計算されますか?

4

3 に答える 3

11

式での評価の順番についてお尋ねしました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;;

ここでも、評価の順序は左から右であることに注意してください。(構造のすべてのチェーンで常に左から右です。)元の質問では、これらすべての新しい変数を、、、letではなく「x」と呼ぶことにしました。これはほとんどの人を混乱させます。この種のコーディング スタイルは避けたほうがよいでしょう。xyz

しかし、変数の名前を正しく変更したことを確認するにはどうすればよいでしょうか。なぜ「let x=y+2 で x=1 にする」のではなく、「let x=y+2 で x=1 にする」のですか? このx=x+2ビジネスはかなり混乱しています!さて、 の評価を理解する別の方法がありlet x=aaa in bbbます。コンストラクト

  let x=aaa in bbb

に適用される次のクロージャで常に置き換えることができますaaa

  (fun x -> bbb) aaa

このように書き直すと、次の 2 つのことが簡単にわかります。まず、OCAML は、「aaa」が評価されるまで、クロージャ内の「bbb」を評価しません。(このため、 の評価は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

のように書き直される

 (fun x -> let x=x+2 in let x=x+3 in x) 1

次に、内部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

ここで、各関数内の関数の引数の名前を変更しましょう。これは、コードの意味を変更せずにいつでも実行できます。

 (fun x -> (fun y -> (fun z -> z) y+3) x+2 ) 1

これは

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

このようにして、変数の名前が正しく変更されたことを確認できます。

于 2012-04-18T08:59:33.587 に答える
4

括弧を想像してください:

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

次に、 x の別の宣言でカバーされていない x を (x=1) に置き換え、最も外側の を削除しletます。

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

評価:

let x = 3 in (let x = (x+3) in x)

代わりの:

let x = (3+3) in x

評価:

let x = 6 in x

代わりの:

6
于 2012-04-16T22:51:33.267 に答える
4

(これはコメントとしては少し長いので、ここに小さな追加の回答があります。)

Chuck が指摘するように、この式にはクロージャーが含まれていません。唯一の複雑さは、スコープ ルールによるものです。OCaml のスコープ規則は通常のものです。つまり、名前は最も近い (最も内側の) 定義を参照します。式では:

let v = e1 in e2

変数vは では表示されません (つまり、名前を付けることができません) e1。(たまたま) その名前の変数が に現れるe1場合、それは (別の) の外部定義を参照する必要がありますv。しかし、 newvは (もちろん) で名前を付けることができe2ます。したがって、式は次と同等です。

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

こっちの方が分かりやすい気がしますが、意味は全く同じです。

于 2012-04-16T23:25:07.433 に答える