PostScript の変数の評価
http://www.hizum.net/diary/?date=20060913#c03 より。手続き A 内で変数を評価するとき、手続きが生成された時点での値を使いたい場合どうすればいいかという話です。長くなったので、コメント欄ではなく、こちらに書きます。
まず、
- hoge 部分に {} があり、その中に評価したい変数がある場合それが評価されない
GS> /rate 116.78 def GS> {true{rate div}if} [exch{dup where{exch get}if}forall] cvx GS> == {true {rate div} --if--}
- hoge 内の fuga がどこかで定義した手続きの場合、これで作られる手続きは、実行しても fuga の部分が実行されず fuga の中身をスタックに積むだけになってしまう
GS> /fuga {foo} def GS> /bar {fuga} [exch{dup where{exch get}if}forall]cvx def GS> bar GS> == {foo}
の2つですが、もうちょっと頑張ればどうにかなります。
/executable_array? { dup type /arraytype eq 1 index type /packedarraytype eq or 1 index xcheck and } def /eval_key{ [ exch { executable_array?{ eval_key }{ dup where{ exch get executable_array?{ /exec cvx }if }if }ifelse }forall ] cvx }def
を定義すれば、
GS> /rate 116.78 def GS> {true{rate div}if} eval_key GS> == {true {116.78 --div--} --if--} GS> /fuga {(Hello)=} def GS> /bar {fuga} eval_key def GS> bar Hello
うまくいきます。……と思ったけど fuga が再帰していたら、fuga を再定義したとき挙動が変わってしまいますね。
……次行ってみよう
- hoge の部分で一時的な変数が使いたい時、その時点の辞書スタックで既に定義されている変数名を使ってしまうと評価されてしまう
これは、手続きを生成した時点で、辞書スタックのトップにある辞書で定義されている名前だけを評価すれば、あまり予想外の振る舞いをしないのではないかと思いました。
/eval_currentdict_key{ [ exch { % executable_array? は上で定義したもの executable_array?{ eval_currentdict_key }{ currentdict 1 index known{ load executable_array?{ /exec cvx }if }if }ifelse }forall ] cvx }def
と定義すると、
/rate 0.5 def /gen_yen_to_dollar{ 0 dict begin /rate 116.78 def /hoge{(大金だ!)=}def { 1 dict begin /a4 exch def a4 10000 gt{ hoge a4 rate div }{ a4 rate div }ifelse end }eval_currentdict_key /rate 2.0 def end }def /rate 3.14 def /yen_to_dollar gen_yen_to_dollar def
とした時、
GS> 980 yen_to_dollar = 8.39185 GS> 20000 yen_to_dollar = 大金だ! 171.262
のようになります。(この場合も再帰があると再定義で挙動が変わってきます。)
ここまで来ると、元の OCaml の単一代入からはかなり遠ざかっているような気がします。(代入は 1 回だけという制限があれば、元の記事の closure で済んでしまうのだな)