最近、ハッカーとペインターの本を読みました。著者は、Lispマクロは他の言語のマクロよりも非常に強力で特別であると述べました。
ELispのマクロを学び始めましたが、それでもどのような特別な使い方がわかりませんか?それとC/C++マクロの違いがわかりません。
誰かが私のためにそれを説明できますか?
最も重要なポイントは次のとおりです。
Lispコードはリストとして表され、Lispマクロを使用すると、Lispのすべてのリスト処理機能(Lispが適しているものです。LISPはLISt Processingの略です)を使用して変換できます。(同像性)ただし、C / C ++プリプロセッサマクロは、単なるテキスト置換です。つまり、より複雑な変換を実行するには、C / C ++プリプロセッサマクロへの入力を自分で解析する必要があります(通常、これらの言語ではパーサーにアクセスできません)。あなたはできませんコードを変換するには、すべてのC /C++または手元にある言語を使用します。これらの単純なマクロ機能は、実際の抽象化よりも、小さな省略形(または型システムのバイパス、パフォーマンスの回避策など)に適しているようです。(より複雑なタスクにそれらを使用できなかったわけではありませんが、すぐに混乱します。)
Lisp構文は、通常の中括弧言語よりもはるかに規則的です。優先順位規則、中置演算子、またはステートメントと式の違いについて心配する必要はありません。
Lispマクロとは対照的に、私が知る限り、C / C ++プリプロセッサマクロでは、プリプロセッサは1つのパスしか作成しないため、フープを飛び越えずにマクロ定義内でマクロを簡単に使用することはできません。
C / C ++スタイルのプリプロセッサマクロに新しいシンボルを導入する簡単な方法はありません(私が知っていることです)。( CLスタイルのマクロでは、gensym
その周りに構築された抽象化with-gensyms
などを使用できます。また、主にスキーム方言で使用される衛生的なマクロシステムもあります。)
Lispのバッククォートされた式は、マクロが展開されるコードを構築するための非常に便利な穴埋めアプローチです。
全体として、Lispマクロを使用したメタプログラミングは、C /C++プリプロセッサを使用したアプローチよりもはるかに便利です。実際には、これは、Lispの比較的新しい初心者でさえ、それほど面倒なことなく、彼自身のループ構造または他の制御構造を作成できることを意味します。もう少し経験を積むと、より複雑なDSLの作成も比較的簡単になります。これをC/C++プリプロセッサと比較してください。C/C ++プリプロセッサでは、これらのタスクはおそらく、勇敢な人だけのために予約された、ある種の黒魔術と見なされます。
簡単な例として、C /C++プリプロセッサを使用して次のようなものを書いてみてください。
(defmacro bif ((var expression) then &optional else)
`(let ((,var ,expression))
(if ,var ,then ,else)))
bif
これは、式を評価し、それを特定のシンボルにバインドし、スコープ内のバインディングを使用してthen
orelse
ブランチを条件付きで実行する新しい制御構造(「バインディングif」)を導入します。正しくネストされ、期待どおりに機能します。さて、このようなことは、Lispプログラマーなら誰でもすぐに書くことができます。それはとても簡単なので、Lispプログラマーは通常、新しい構成の必要性を感じたときに躊躇しません。言語デザイナーと言語ユーザーの間の障壁はあいまいです。
(C / C ++プリプロセッサを使用してこれを書くことができたとしても、次のステップ、つまりLispのようなものcond
や新しいループ構造を書くことははるかに複雑になります。)
Lispマクロを使用すると、C++マクロよりも深いレベルで言語を変更できます。Lispマクロは、コンパイル段階で実行されるコードの一部であり、パラメーターの評価を制御できます。
一例として、Lispはコンパイラが処理しなければならない約25の「特殊な形式」に基づいています。Lispの残りの部分は、これらの特別な形式の上に繰り返し存在することができます。私はELispに精通していませんが、CommonLisploop
機能はマクロを介して実装されています。言語を拡張することができます-多くの場合、Lispには条件文用の特別な形式が1つしかなく、他のすべてはLispでその上に実装されます。defun
関数を定義するために使用される構造である、はマクロとして実装できると思います。
C ++マクロは強力ですが、プリプロセッサによって実行されます。つまり、実行できる機能が制限されています。Lispマクロはコンパイル環境で実行されているため、プログラマーが定義した関数を含め、関数を実行して入力を書き換える方法を決定できます。
この応答はかなり複雑で曖昧なので、もっと時間があれば誰かがより良い応答を提供できることを願っています。パスカルのように、この答えを長く曖昧にしてしまったことをお詫びします。