仮引数の評価
Lispの初歩的な事で納得できねぇと悶々していたけど、納得できた。
評価について。
クオートが付いてるのは評価されるとクオートが一つ剥がれてシンボルやリストそのものになる。クオートが付いていないリストは評価される=関数が実行される。
まず、簡単な関数。
(defn a1 [test] (if test (println "hello")))
実行すると、期待通り。
user> (a1 true) hello nil user> (a1 false) nil
次に実行する関数を引数で渡せるバージョン。
(defn a2 [test s] (if test s))
呼び出すときに実行したいリストをそのまま引数に渡すと、a2はマクロではなく関数なので最初に引数を全て評価してしまう。
user> (a2 false (println "hello")) hello nil
実行したいリストにクオートを付けて、評価を一つ遅らせればいいだろうと考えてやってみると、
user> (a2 true '(println "hello")) (println "hello") user> (a2 false '(println "hello")) nil
あれ、渡したリストが実行されること無くそれ自身が返ってきてしまった。
eval すれば期待通りの動作をする。
(defn a3 [test s] (if test (eval s)))
user> (a3 true '(println "hello")) hello nil user> (a3 false '(println "hello")) nil
しかし、何で a2 ではダメなんだろう。関数の中ではクオートが剥がれた(println "hello")になってるはず。クオートされていないリストは関数が実行されるんじゃ・・。
とここで分かった。関数内の仮引数の存在を忘れていた。仮引数は評価されて初めて値を返してくるシンボルなのだという当たり前のことを理解できていなかった。シンボル=ポインタ。シンボルが評価されると関連付けられた値を返してくる。