# レキシカルスコープでダイナミックスコープを実装する。(Ruby編) _published: 2010/08/28_ ![alt](http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/shunsuk/20100828/1282999101) よく考えたら、ダイナミックスコープを採用している言語を使ったことがありませんでした。まあ、よく考えなくても、使ったことはないのですが。というわけで、レキシカルスコープなRubyで、ダイナミックスコープを実装してみます。 valvallowさんによると、レキシカルスコープなSchemeでダイナミックスコープを実装したマクロや、ダイナミックスコープなEmacs Lispでレキシカルスコープを実装したマクロがあるのだとか。その話を聞いたのが、事の発端です。案の定です。 まずは、こんな実装。 ```ruby def method_missing(name, *args) $context.eval(name.to_s) end def output puts x end def test x = 123 $context = binding output() end test() #=> 123 ``` `output` メソッドの中で定義されてない `x` を使おうとすると、 `method_missing` が呼ばれるのを利用しました。`output` 呼び出し直前の `binding` を保存しておく必要があります。これはメソッド呼び出しをフックしても解決しません。メソッドが呼び出された時点で、コンテキストが変わってしまいます。 メソッド呼び出し直前に `$context = binding` の1行をいれなければならない。おもしろくないですね。そもそも、すべての変数をダイナミックスコープにしなくてもいいんじゃないでしょうか。Common LispやPerlのように、スコープを選択できると便利です。 そんな、実装。 ```ruby def method_missing(name, *args) eval("$#{name}") end def local(name, val) eval("$#{name} = val") end def output puts x end def test local :x, 123 output() end test() #=> 123 ``` 変数の定義が特殊すぎますね。` local x = 123` としたいところですが、 `=` は制御構造なのでカスタマイズできません。また、 `.call` としなくていいのであれば、 `proc` を使う方法もあるのですが。 と書いてみましたが、どちらの実装も変数がリードオンリーなんですよね。とりあえず、この辺でやめておきます。Lispのマクロはすごいなー。