マクロすごい。すごいマクロ。
マクロすげええええええええええええええ
このブログを書くようになったきっかけである9LISPからかれこれ1年半が経ちました。
当時、Lispを勧められたとき「何が凄いんですか?」って聞いたら「ifが自分で書けるんだよ」と某@valvallowさんに言われたのを今でも覚えています。あと、valvallowさんに「LispはFortranの次に古い言語で、1958年にジョン・マッカーシーによって"発見"されたんです。ちなみに僕のお父さんも1958年生まれなので、つまり僕のお父さんはLispです!」*1って言われたのも覚えています。ついでに言うと当時の僕はFortranってなんとなく名前しか知りませんでした。むしろ、今でも名前しか知りません。FLOat Processing。
僕がだいたい初対面の人にLispの話をするとき、「1958年に発見された言語です」ってひとことふたこと言うのは、だいたいvalvallowさんの喋った内容を覚えてしまっているので、そのまま使っていたりします。(・ω<)
閑話休題。当時の僕は「ifが書けたら何が嬉しいんですか?それメソッドじゃダメなんですか?」みたいなことを、言っていた気がします。バカの子です。
実際、Gaucheでコード書いてて、define-syntaxを少し書いてみても「何が嬉しい」のかさっぱり分かりませんでした。
かと言って、あんまり必要だと感じるシーンがなかったので、今まで無視してきました。ダメな子です。
「マクロがなんか凄いらしい、ふーん…」みたいな。いや、むしろマクロ知らないのにLisp好きとか言ってたのかよ!って後ろから刺されそうな勢いですが、僕のLispに対する愛は本物です。
というわけで前置きが長くなりましたが、マクロ何が凄いって特殊形式を自然に書けちゃうとこなんですねー。
my-ifというのをさくっと書いてみるとこんな感じ。
(define-syntax my-if (syntax-rules () ((_ test consequent alternative) (cond [test consequent] [else alternative]))))
で、1年半前からの僕の疑問であった「それメソッドじゃダメなんですか?」に対する答えはダメです。っていうのが正解で、例えばこんな風にふつうにmy-if2を定義したとします。
(define (my-if2 test consequent alternative) (cond [test consequent] [else alternative]))
ふっつーの手続きですね。これでもなんとなく動きます。なんとなくは。単純な分岐くらいなら動きます。
(define x 10) (my-if2 (> x 10) "hoge" "fuga") ;;=> "fuga"
このくらいならね。
これでダメなのが評価したくないものがあるときです。SICPにも書いてあったけど、特殊形式であるifやcondは全ての式を評価するわけじゃないのです。ifのtestが#tならelseの式は評価する必要がないので、評価しないままでいたいのです。
先ほどのmy-if2はこういう式を書くと、ボロが出ます。
(define x 10) (my-if2 (> x 10) (print "hoge") (print "fuga")) ;;=> hoge ;;=> fuga
で、一番最初にdefine-syntaxで定義したmy-ifだと、普通のifと同じような動きをしますよっと。(これelse省略できないやつだけど、もう少し書き足せばelseの省略もできる)
他にもマクロで書くと同じ手続きを何度も呼び出すときなんかは有利らしい。まだ良くわかってない。実行面での最適化?がされるんだと認識してます。
で、なんで僕はLOLとか持ってるのに、マクロを今まで理解してなかったんだって言われたら、単純な話読んでないんです、すみませんってことになるんですが、初めての人のためのLISP読んでて半分くらい読んだところでようやくマクロの話が出てきて、「おー!」って納得したのが今日です。はい。プログラミングGaucheもなんだかんだで半分くらいまで読んで、その後あっちにいったりこっちにいったりしてますね。。*2
まぁ良いんです。バーナード嬢曰く「一度読んだらもう二度と読む前には戻れない。読む前のワクワク感を失った人に対してはむしろ優越感を覚えるわー」とのことなので、こうやって色んなことを知る楽しみがまだあると思えば、悲観するものでもないかなと。
一年半ずっと大事にしていた疑問がようやくすっきりと解決できた。マクロ凄い。