|
<式> | ::= | … |
| | (set <識別子> <式>) |
Expressed Value | = | 整数 (…, -2, -1, 0, 1, 2, 3, …) + 関数値 |
Denoted Value | = | (整数 + 関数値) への参照(アドレス) |
(set x (add1 x))という式において,最初の x の出現の示すものは,変数の denoted value,すなわち束縛されているアドレスであり,ふたつめの出現の示すもの は,束縛されているアドレスの「内容」(expressed value)である.このよう に,代入のある言語では,変数に「二種類の値」が関連づけられていると考え, アドレスとしての値を左辺値(L-value),その内容としての値を 右辺値(R-value) と呼ぶことがある.これらの名前は,C 言語の x=x+1; といった代入文で,左辺の x はアドレスであり,右辺の x は その内容を示すことに由来する.これに対し,Objective Caml の参照型は,これら の概念をきっちりと分けており,x が int ref 型とすると,x と書い た場合は常にその「左辺値」を示し,x の「右辺値」を参照する際には常に !x と明示的に書かなければならない.
(let ((counter 0)) (let ((get (lambda () counter)) (inc (lambda () (let ((d (set counter (add1 counter)))) 0)))) (let ((d (inc))) (let ((d (inc))) (get)))))d はダミーの変数で,let とともに用いて式の実行の順序付けを している.counter の内容を1増やす関数 inc を2回呼んで, counter の内容を get で得ており,全体の評価結果は 2 になる.このふたつの関数は,値をパラメータとしてやり取りするのではなく, 変数の状態を変更することで行っている.また,counter を関数に プライベートなものとして宣言することで,隠れた状態を実現できる.
(let ((inc_and_get (let ((counter 0)) (lambda () (let ((d (set counter (add1 counter)))) counter))))) (+ (inc_and_get) (inc_and_get)))2回の inc_and_get の呼出しは,呼出し時点の内部状態 (counterの値によって)それぞれ違う値を返している.
(let ((x 100)) (let ((p (lambda (x) (let ((d (set x (add1 x)))) x)))) (+ (p x) (p x))))の値は 202 である.つまり,p の呼び出し毎に,新しいアドレスが 実引数のために割り当てられ,そこに set で代入されても,p の 外側の x には影響をおよぼさないのである.
syntax.ml:
type exp = ... | Assign of id * exp
core.ml:
type exval = ... and dnval = exval ref ... let extend_env_rec syms procs env = let vec = Array.make (List.length syms) (ref (IntV 0)) in ... iteri (fun i (ids, body) -> vec.(i) <- ref (ProcV (ids, body, newenv))) procs; let rec eval_exp env = function ... | Var sym -> !(apply_env sym env) | Prim (p, es) -> let args = eval_prim_rands env es in ... ... | Assign (id, exp) -> let arg = eval_exp env exp in let idref = apply_env id env in begin idref := arg; IntV 0 end and eval_rands env = function [] -> [] | e :: rest -> ref (eval_exp env e) :: eval_rands env rest and eval_prim_rands env = function [] -> [] | e :: rest -> eval_exp env e :: eval_prim_rands env rest
Figure 14: 変数への代入
<プログラム> | ::= | <式> |
<式> | ::= | … |
| | (begin <式1> … <式n>) |
Expressed Value | = | 整数 (…, -2, -1, 0, 1, 2, 3, …) + 関数値 |
+ Expressed Value への参照 | ||
Denoted Value | = | Expressed Value |
(let ((g (let ((count (ref 0))) (lambda () (let ((d (setref count (add1 (deref count))))) (deref count)))))) (+ (g) (g))