ここには、100% 理解できない小さな問題があります。
let x = 1 in let x = x+2 in let x = x+3 in x
この式の結果が 6 であることはわかっていますが、この式の計算順序を確認したいだけです。どの部分が最初に計算されますか?
ここには、100% 理解できない小さな問題があります。
let x = 1 in let x = x+2 in let x = x+3 in x
この式の結果が 6 であることはわかっていますが、この式の計算順序を確認したいだけです。どの部分が最初に計算されますか?
式での評価の順番についてお尋ねしましたlet x=1 in let x=x+2 in ...
。順番は「左から右」!のチェーンがある場合let a=b in let c=d in ...
、評価の順序は常に左から右です。
ただし、あなたの例には紛らわしい部分があります。すべての構成で同じ変数名を使用しました。のようなものが表示されるため、これは混乱を招きます。これは、「」の値を「再定義」または「変更」しているように見えます。しかし、OCAML では実際に「x」の「変更」は行われません! すでに上で指摘したように、ここで何が起こるかは、新しい変数が毎回導入されるため、あなたの例は完全にx
let
let x=x+1
x
x
let x = 1 in let y = x+2 in let z = y+3 in z;;
ここでも、評価の順序は左から右であることに注意してください。(構造のすべてのチェーンで常に左から右です。)元の質問では、これらすべての新しい変数を、、、let
ではなく「x」と呼ぶことにしました。これはほとんどの人を混乱させます。この種のコーディング スタイルは避けたほうがよいでしょう。x
y
z
しかし、変数の名前を正しく変更したことを確認するにはどうすればよいでしょうか。なぜ「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
このようにして、変数の名前が正しく変更されたことを確認できます。
括弧を想像してください:
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
(これはコメントとしては少し長いので、ここに小さな追加の回答があります。)
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
こっちの方が分かりやすい気がしますが、意味は全く同じです。