本を読む

読書やコンピュータなどに関するメモ

「L2Lisp in Ruby」をPerlで

 CodeZineの記事より。

 RubyでLispインタプリタを作る記事。静的スコープや末尾再帰最適化を含んでいるそうな。さっそくPerlに移植してみた。

 ただし、オープンソースライセンスではなくて「Oki Software Co., Ltd.」さんが著作権を保持しているので、作ったコードは公開できない。

追記(2007.7.29):作者さんから「ライセンスはMITライセンスなので、好きなようにできます」とのご連絡をいただきました。ありがとうございます。

 そのまんま文法を置き換えただけなので、Lisp処理系を作ったことがあって、RubyとPerlをかじった人なら、誰でもさっそく移植できると思う(オリジナル実装がすげーということ)。

 とりあえず変更した点をメモ。

ファイル構成

 Perlの場合、1クラス1ファイルが使いやすいと思う。そこで、こんな構成にした。

-+- l2lisp.pl                     … トップレベル
 +- lib -+- L2Lisp.pm             … L2Lisp.rbのInterpクラス相当
         +- L2Lisp -+- Util.pm    … L2Lisp.rbでクラスじゃないないメソッド相当
                    +- Cell.pm    … L2Lisp.rbのCellクラス相当
                    +- Reader.pm  … L2Lisp.rbのReaderクラス相当
                    +- Symbol.pm  … シンボルのクラス
                    +- String.pm  … 文字列のクラス

シンボルのクラスを定義

 L2Lisp.rbでは基本データ型にRubyのクラスをそのまま使っている。だが、Perlにはシンボル相当のデータ型がない(と思う)。そこでL2Lisp::Symbolクラスを作った。

文字列のクラスを定義

 Perlでは原則的に文字列と数値が区別できない。L2Lispでもそういう仕様にしてごまかそうかと思ったが、prin1(S式の出力)がかっこよくない。そこで、L2Lisp::Stringクラスを作った。

例外クラスを使う

 L2Lisp.rbでは、実行時エラーにRubyの例外をそのまま使って処理している。Perlで例外を使うには、こんな感じになる。

eval {
  # …
  die "hogehoge";  # 例外を発生させる
  # …
};
if ($@) {
  # 例外処理
}

 ただし、L2Lisp.rbでは例外の引数にオブジェクトを渡している。なので、Exception::Classモジュールを使って楽をした。

eval {
    # …
    MyException->throw(message=>"yabai", exp=>$obj);  # 例外を発生させる
    # …
};
if ($@) {
    if (MyException->caught) {
        # MyExceptionの例外処理
    } else {
        ref($@) ? $@->rethrow : die $@;
    }
}

 細かいところでは、Perlでは、eval{}で例外を捕捉するとreturnまで捕捉されてしまう。そこで、eval{}の中でreturnを使わないように変更した。

パフォーマンス比較

 たらい関数で比較してみる。

$ cat tak.l
(defun tak (x y z)
  (if (>= y x) z
    (tak (tak (- x 1) y z)
         (tak (- y 1) z x)
         (tak (- z 1) x y))))
(prin1 (tak 18 12 6))
(terpri)
$ time ruby L2Lisp.rb tak.l
7

real    0m16.810s
user    0m14.613s
sys     0m2.164s
$ time perl l2lisp.pl tak.l
7

real    0m27.087s
user    0m27.050s
sys     0m0.012s

 …ごめんなさい、出直します。

コメント

管理人のみ閲覧できます

このコメントは管理人のみ閲覧できます

コメントの投稿

管理者にだけ表示を許可する

トラックバック

http://emasaka.blog65.fc2.com/tb.php/261-ff257d86

続・「L2Lisp in Ruby」をPerlで

「L2Lisp in Ruby」をPerlでreal 0m27.087suser 0m27.050ssys 0m0.012s …ごめんなさい、出直します。の続き。 DProfで調べると、eval()が激しく呼ばれていた(たらい関数だからねぇ)

 | HOME | 

Categories

Recent Entries

Recent Comments

Recent Trackbacks

Appendix

emasaka

emasaka

フリーター。
連絡先はこのへん

Monthly


FC2Ad