Ruby の上に Lisp っぽいものを作ってみた。
足し算ができる。
> (+ 10 20) 30
式の実態は Array クラスのオブジェクトとシンボルなどだ。
> (quote (+ 10 20)) [:+, 10, 20]
> (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]