Ruby の上に Lisp っぽいものを作ってみた。

足し算ができる。

> (+ 10 20)
30

式の実態は Array クラスのオブジェクトとシンボルなどだ。

> (quote (+ 10 20))
[:+, 10, 20]

Ruby のコードにコンパイルされてから実行される。

> (compile_sexp RubyLisp (quote (+ 10 20)))
"10.+(20)"

グローバル関数を呼び出すときは . を付ける謎仕様。

> (.puts "hello world")
hello world
nil

メソッドならそのまま書ける。

> (puts STDOUT "hello world")
hello world
nil

関数名には Common Lisp のように #' を付ける。

> (call #'succ 10)
11

ラムダ式が書ける。

> (call (lambda (x) (* 2 x)) 10)
20

関数にブロック引数を渡すときは & を付ける。

> (map (quote (1 2 3)) &(lambda (x) (* 2 x)))
[2, 4, 6]

& はただのシンボルだ。

> (quote (map (quote (1 2 3)) &(lambda (x) (* 2 x))))
[:map, [:quote, [1, 2, 3]], :&, [:lambda, [:x], [:*, 2, :x]]]

変数への代入。

> (setq x 10)
10
> (setq y 20)
20

関数を定義してみよう。

> (def list (&rest items) items)
nil
> (.list x y)
[10, 20]

こういうマクロを書くと・・・

(defmacro rotatef (a b)
  (.list (quote progn)
           (.list (quote setq) (quote tmp) a)
           (.list (quote setq) a b)
           (.list (quote setq) b (quote tmp))
           (quote nil)))

値を入れ替えることができる。

> (rotatef x y)
nil
> (.list x y)
[20, 10]
> (macroexpand RubyLisp (quote (rotatef x y)))
[:progn, [:setq, :tmp, :x], [:setq, :x, :y], [:setq, :y, :tmp], :nil]