Rubyとの連携を考える(1)
私がRubyで書いているLisp方言、 [Nendo]の開発状況続き。
Clojureを参考にする
Clojureの .(dot) operatorを使うやりかたはクラスベースのオブジェクト指向言語との連携を行う上で非常に直感的で良いと思う。 .(dot)はJavaでもRubyでもメソッドやインスタンス変数へのアクセス記号として使われているので、見た目でLisp外のメソッド呼びだしが連想しやすい。 以下はClojureのサイトに掲載されているClojureの例。 Clojure - java_interop
(.toUpperCase "fred")
-> "FRED"
(.getName String)
-> "java.lang.String"
(System/getProperty "java.vm.version")
-> "1.6.0_07-b06-57"
Math/PI
-> 3.141592653589793
Nendoではどうするのか
Clojureの考えかたがそのまま流用出来るかどうか分からないけど、気持ち的にはこんな感じで書きたい。 Lispのreadの呼びだし
(read)
RubyのKernel#readの呼びだし
(.read)
インスタンスのnew
(. new Date)
同じく、インスタンスのnew これは、リーダマクロで (. new Date) に展開されることを想定。
(Date.new)
RubyのKernel#openでファイルを開いてすべての行を読みこみ
(let1 f open( "file.txt" )
(f.readlines.to_list))
ブロックの最後に自動でクローズしてくれるwith-openも欲しい。 ファイルを読みこんでソートして表示する例。
(for-each
print
(with-open( "file.txt" )
(lambda (f)
(f.readlines.sort_by.to_list)))
多分、Schemerが見てもRubyistが見ても両方キモチワルイと言うだろうな… とりあえず、ここまで動けば発表のネタにはなるでしょう。 どうです?ちょっと遊んでみたくなりました?
まずは、ターゲットユーザが自分ひとりなので、自分がスラスラ書ける仕様を試してみるつもりです。
コメント by sion:
なかなか浮世離れした高尚な遊びですね。
当方、「python が Windows-31J を理解してくれないから、パッチあてよう!」なんて、極めて野暮なことをやっております(^^;
ようやく今の職場も SubVersion 導入!(いままではVSS) こないだ Wikiも立ち上げたし、今度は trac でも導入しようかと。
まったく関係ない話でしたね。
ネンド遊びができそうになってきたら、是非使わせてくださいね。
コメント by shiro:
foo.barをリーダマクロでS式として読むというのは前にやったことがあるんですが (その時は foo.bar を (-> foo bar) としていた)、
リーダマクロを素直に実装するとひとつのトークンからひとつのS式への変換になるので、例えばDate.newというトークンが (. new Date) に変換されることになると思います。つまり (Date.new) という式は ((. new Date)) になっちゃう。
リーダマクロにsplicing (リーダマクロが返したリストを ,@ のように親のリスト中に展開する) を許せば (Date.new) を (. new Date) にすることは可能ですが、そうするなら次のような場合の動作をうまく考えておく必要があります。
(foo bar.baz) ; splicingすると (foo . bar baz) になっちゃう。
(foo . bar.baz) ; こんなふうに使われたらどうする?
コメント by kiyoka:
なかなか浮世離れした高尚な遊びですね。 そうですね。世の中ドラクエが発売されたというのに、こんな遊びを見つけてしまいました。 なかなかどうしてゲームに匹敵する面白さです。 ネンド遊びができそうになってきたら、是非使わせてくださいね。 あと何ヶ月かしたら、Rubyと組み合わせて遊べるようになると思います。 よろしくお願いします。
コメント by kiyoka:
shiroさんにコメントをもらってからいろいろ考えてみたんですが、リーダマクロで単順に変換するわけにはいかなそうですね。
例えば、
(Date.new) は (. Date new) に展開されて欲しいけれども、
(Date.new.strftime “%X”) は (. (. Date new) strftime “%X”) に展開されて欲しいと思ったら単純にはいかなさそうです。
また、Clojureでも (set! (instance.member_val) 20) のように set!で インスタンス変数を更新できる様ですが、それも含めて考えると、統一的なルールで処理出来るかどうか考えている所です。
もうすこし考えが進んだらブログエントリを書きます。
※ それから、このエントリで 『リーダマクロで (. new Date) に展開されることを想定。』と書いていた所は (. Date new)の間違いでした。すみません。
コメント by sion:
なかなか浮世離れした高尚な遊びですね。
当方、「python が Windows-31J を理解してくれないから、パッチあてよう!」なんて、極めて野暮なことをやっております(^^;
ようやく今の職場も SubVersion 導入!(いままではVSS) こないだ Wikiも立ち上げたし、今度は trac でも導入しようかと。
まったく関係ない話でしたね。
ネンド遊びができそうになってきたら、是非使わせてくださいね。
コメント by shiro:
foo.barをリーダマクロでS式として読むというのは前にやったことがあるんですが (その時は foo.bar を (-> foo bar) としていた)、
リーダマクロを素直に実装するとひとつのトークンからひとつのS式への変換になるので、例えばDate.newというトークンが (. new Date) に変換されることになると思います。つまり (Date.new) という式は ((. new Date)) になっちゃう。
リーダマクロにsplicing (リーダマクロが返したリストを ,@ のように親のリスト中に展開する) を許せば (Date.new) を (. new Date) にすることは可能ですが、そうするなら次のような場合の動作をうまく考えておく必要があります。
(foo bar.baz) ; splicingすると (foo . bar baz) になっちゃう。
(foo . bar.baz) ; こんなふうに使われたらどうする?
コメント by kiyoka:
なかなか浮世離れした高尚な遊びですね。 そうですね。世の中ドラクエが発売されたというのに、こんな遊びを見つけてしまいました。 なかなかどうしてゲームに匹敵する面白さです。 ネンド遊びができそうになってきたら、是非使わせてくださいね。 あと何ヶ月かしたら、Rubyと組み合わせて遊べるようになると思います。 よろしくお願いします。