kiyokaのブログアーカイブ

Archive of old blog posts

Gaucheのobject-applyのようなことをしたい

私がRubyで書いているLisp方言、 [Nendo]について。

Gaucheでは次のようなことができる。Rubyでいうところの

/abc/ =~ "abc"

と同じ処理が

(#/abc/ "abc")

のように書ける。

これは、Gaucheのリファレンスマニュアルをちゃんと読む前は、きっと内部(reader)で #/abc/ のリテラル部分がこんな感じのコードに変換されているのだろうと思っていた。

(lambda (str)
  (rxmatch #/abc/ str))

でも、以下の例ように引数に正規表現リテラルが来る場合はまずい。 #/abc/ 部分が (lambda …) にされてしまったら、rxmatchはどう定義すればいいのか… いったい引数の型チェックはどうすればいいの?

(rxmatch #/abc/ "abc")

で、Gaucheのリファレンスマニュアルを見ると、『適用可能なオブジェクト』という仕組みで実現されている。これは面白い。 Gauche ユーザリファレンス: 6.16 制御

6.16.2 適用可能なオブジェクト

Gaucheでは、特別な組み込みの機構によって任意のオブジェクトを「適用可能」 にすることができます。

Generic Function: object-apply object arg …

 手続きでもジェネリックファンクションでもないオブジェクトが何らかの
 引数に適用されたとき、そのオブジェクトと引数がジェネリックファンク
 ションobject-apply に渡されます。

 この機能は、具体的な例を挙げた方が説明し易いでしょう。

例えば、次のような式を評価しようとしたとします。

  ("abcde" 2) 

オペレータは文字列に評価されますから、手続きでもジェネリックファンクショ ンでもありません。そこで、Gaucheはこの式を、あたかも次のような式が与え られたかのように解釈します。

  (object-apply "abcde" 2) 

デフォルトでは、を引数とする object-applyのメソッド は定義されていないので、この式はエラーになります。しかし、次のようなメ ソッドを定義すると:

  (define-method object-apply ((s <string>) (i <integer>))
     (string-ref s i))                                     

最初の式はまるで文字列が整数に適用されたかのように動作します。

(“abcde” 2) → #\c

[Nendo]でGaucheのモノマネをしようとすると、マルチメソッドディスパッチャを実装しないといけないのかー。 しかし、この仕組みは凄く柔軟性があって上述の (#/abc/ “abc”) のような記述を拡張していけるので魅力的だ。 ただ、うまくマルチメソッドディスパッチを実装しないと非常に実行効率の悪いものが出来上がりそう…. (Rubyでいうところの method_missing と同じように便利で強力だけど反面重いので気をつけて使えというものになりそう)

[Nendo]でもマルチメソッドディスパッチとobject-applyを実装して実現するのは楽しそうだけど、いいのかな。 もうちょっと考えてみよう。 [Nendo]では、将来Rubyのクラスを定義できるようにするのか等、まだ考えきれていないところがたくさんあるので、それと合わせて考える必要があるなぁ。


コメント by shiro:
マニュアルへのパーマリンクはこんな感じで貼れますよ。p=の後の単語をindexから探してそこにジャンプするcgiになってます。 http://practical-scheme.net/gauche/man/?l=jp&p=object-apply


コメント by kiyoka:
shiroさん、ありがとうございます。 ブログ記事中のリンクをパーマリンクに直しておきました。

コメント by shiro:
マニュアルへのパーマリンクはこんな感じで貼れますよ。p=の後の単語をindexから探してそこにジャンプするcgiになってます。 http://practical-scheme.net/gauche/man/?l=jp&p=object-apply