2013年8月9日金曜日

((Rubyで) 書く (Lisp) インタプリタ)

最近Rubyを始めました。

手始めにLispインタプリタを書いてみます。

元ねたはPeter Norvigの (How to Write a (Lisp) Interpreter (in Python)) (日本語訳: ((Pythonで) 書く (Lisp) インタプリタ))です。

(ちなみに以前、Rでも同じことをやりました: ((Rで) 書く (Lisp) インタプリタ))

コード

Gistに上げておきました。 変なところがあったら教えてください。

遊び方

$ ruby lisp.rb 
lisp.rb> (+ 1 2 3)
6
lisp.rb> (define add2 (lambda (x) (+ x 2)))
#<Proc:0x00000001647958@lisp.rb:62 (lambda)>
lisp.rb> (add2 40)
42
lisp.rb> (define map (lambda (f l) (if (null? l) (quote ()) (cons (f (car l)) (map f (cdr l))))))
#<Proc:0x0000000164f1a8@lisp.rb:62 (lambda)>
lisp.rb> (map add2 (list 10 20 30))
(12 22 32)
lisp.rb> 

感想

Rubyを使ってみて思ったことをメモしておきます。

  • Perlっぽい

    • メソッドのかっこを省略できる
    • ifとかwhileを後置できる
  • Lisp(関数型)っぽい

    • Symbol
    • いろんなものが値を返す(ifとか)
    • returnを省略できる
  • オブジェクト指向

    • 何でもオブジェクト!
    • mapとかの高階関数がメソッドなのはなんだか違和感があるけど、 メソッドチェインができるのは良いかも。

割と良い感じです。もうちょっと使ってみます。 ワンライナーとかちょっとしたスクリプトとかPerlのかわりに使ってみようかな。

参考文献

同じことをやっている方は他にもいます。
元ねたのページ のコメントで紹介されていた 以下の実装が簡潔で素敵です。 わからないところはこちらをチラ見しながら作りました。

(追記)

その後少し手を加えて、REPLで式の途中に改行を入れられるようにしました。
(上に貼ってあるGistは修正後です。)

こんな感じに入力できます。

lisp.rb> (+ (* 3
               (+ (* 2 4)
                  (+ 3 5)))
            (+ (- 10 7)
               6))
57
lisp.rb> 

思ったより少ない変更で実現できました。 (Gistの履歴)