218 views
## CollegeUnion Wiki [topに戻る](https://hackmd.io/s/rkFqu9xKg) [Common Lispに戻る](https://hackmd.io/s/BycE9MMKl) # Common Lisp **書きかけ御免** ### Lisp is simple, and the simple thing is the right thing Lispは簡単だし、簡単なことは正しい。つまりLispは正しいのです! そんなLispで最も難しそうに見えるマクロですが、全然難しくありません。入門1日目の君にも書ける! ## 予備知識 分かる方はすっ飛ばしてください。 ### データモードとコードモード Lispには2つのモードがあります。普段はコードモードで、特別な文字を使った時だけデータモードになります。その特別な文字の代表例がシングルクォーテーション`'`です。データモードでは、適用範囲内の文字列の**評価が止まります**。何を言っているのか分からねぇと思うので、コードとその評価結果を示します。 まずはコードモードだけの例。 ```lisp (defvar foo "bar") => FOO foo => "bar" (+ 1 2) => 3 ``` そしてデータモードの例。 ```lisp 'foo => FOO '(+ 1 2) => (+ 1 2) ``` 違いは分かりますよね?単に後ろの文字列が返ってきているようにも見えますが、そういうわけではありません。このデータモードで生成された値の型を調べてみましょう。 ```lisp (type-of 'foo) => SYMBOL (type-of '(+ 1 2)) => CONS ``` 異なる二つの型が出てきました。これで、このシングルクォーテーションによって**見た目通りの値が返ってくる**ことが分かりました。 (このデータモード、単にソースコードをパースして構文木を作成しているだけだということに気付きますか?) ## マクロ Common Lispのマクロはコンパイル時に展開されます。 定義方法も関数とほとんど変わりません。 ```lisp (defun hello (x) (format t "~Aさんこんにちは。~%" x)) (hello "かばん") => NIL かばんさんこんにちは。 (defmacro great () '(format t "すごーい!~%")) (great) => NIL すごーい! ``` うん…。ただこれだけだとマクロの利点が分からないし、別に「すごーい!」ところもありませんね。これではC言語のマクロと大差無いので、ここで他の特別な文字を導入します。バッククォーテーション`` ` ``とコンマ`,`です。これはリスト表記と共に使われるもので、**指定位置のリスト要素だけ評価**したい時に使います。 ```lisp `(+ 1 ,(* 2 3) 5) => (+ 1 6 5) ``` これをマクロの定義に利用してみます。 ```lisp (defmacro friends (x) `(format t "すごーい!きみは~Aが得意なフレンズなんだね!~%" ,x)) (friends "Common Lisp") => NIL すごーい!きみはCommon Lispが得意なフレンズなんだね! ``` これでマクロの表現力がちょっと増しましたが、まだC言語の域を出ない感じですね。もう少し変わったことをしてみます。 ```lisp (defun double (x) (* x 2)) (defmacro doubled-string (num) (let ((x (double num))) `(write-to-string ,x))) (doubled-string 512) => "1024" ``` 関数を定義して、それをマクロ内で呼び出してみました。ここで確認しておきたいのは、Common Lispのマクロはコンパイル時に展開されるということです。Common Lispにはマクロを展開する関数があるので、それで展開して何が起こっているのか確認してみましょう。 ```lisp (macroexpand '(doubled-string 512)) => (write-to-string 1024) ``` まあ大体予想通りってところでしょうか?この`(doubled-string 512)`は`(write-to-string 1024)`に置き換えられてコンパイルされます。…あれ、**512を1024に置き換えたのは誰?** コンパイル時に展開するのは分かりました。でも、何か間の部分が抜け落ちている感じがしますね。はて? ## 関数とマクロ、どっちが先? 先ほどの例では、マクロ内でユーザー定義関数を呼び出しました。くどいようですが、マクロはコンパイル時に展開されます。さっきの512を1024に置き換えたのは、紛れもなくそのユーザー定義関数です。では、ユーザー定義関数はいつコンパイルされるんでしょうか? Common LispではC言語などと同様に、ソースコードの**上からコンパイルされていきます**。そのため先ほどの場合、ユーザー定義関数はマクロよりも先にコンパイルされているので実行が可能となっています(インクリメンタルコンパイルと呼びます)。この関数を実行するのはコンパイラの仕事で、マクロの戻り値以外の部分はコンパイラへの命令と解釈することも出来ます。つまり**マクロを書くことはコンパイラの処理を書くこと**なんですね。 で、そんな感じでコンパイルされていって、最終的にその**環境が実行ファイルにダンプされる**というわけです。 上からコンパイルされていくとなるとプロトタイプ宣言とかしたくなりますが、依存関係が関数で閉じている場合は警告が表示されるだけで、問題無くコンパイルされます。でも警告が出るとカッコ悪いので基本的に上から順に並べるようにしましょう。 ## マクロによるAPIデザイン (メモ:もう少々お待ちを!)