Scheme マクロを使用した目的は何ですか?[閉まっている]
質問
マクロの例の多くは、ラムダを非表示にすることに関するもののようです。CL の with-open-file。私は、特に PLT スキームでの、マクロのより珍しい使用法を探しています。マクロとマクロのどちらの使用を検討すべきかについて感覚をつかみたいと思います。関数を使って。
解決
私は Scheme マクロのみを使用します (define-syntax
)ラムダ構文の改善などの小さなことについては、次のようになります。
(define-syntax [: x]
(syntax-case x ()
([src-: e es ...]
(syntax-case (datum->syntax-object #'src-: '_) ()
(_ #'(lambda (_) (e es ...)))))))
これにより、書くことができます
[: / _ 2] ; <-- much better than (lambda (x) (/ x 2))
Dan Friedman は、マクロを使用した驚くべきオブジェクト指向の実装を行っています。 http://www.cs.indiana.edu/~dfried/ooo.pdf
でも正直に言うと、すべてが 役に立つ 私が定義したマクロが盗まれました Paul Graham の On Lisp 一般に、より書きやすいです defmacro
(define-macro
PLT スキームでは)。例えば、 aif
かなり醜いです define-syntax
.
(define-syntax (aif x)
(syntax-case x ()
[(src-aif test then else)
(syntax-case (datum->syntax-object (syntax src-aif) '_) ()
[_ (syntax (let ([_ test]) (if (and _ (not (null? _))) then else)))])]))
define-syntax
これは、変数をキャプチャできないことが嬉しい非常に単純なマクロにのみ使いやすいという点で奇妙です。変数をキャプチャできないことに満足している非常に複雑なマクロ DSL 簡単に. 。最初のケースでは、何も考えずにコードを書きたいと考えています。2 番目のケースでは、DSL について十分に考えたので、その一部を syntax-rules
/syntax-case
不可解なバグを避けるために、Scheme ではない言語を使用します。
ただ、Schemeではマクロはあまり使いません。Idiomatic Scheme は非常に関数的であるため、関数型プログラムを作成してからいくつかのラムダを非表示にしたいことがよくあります。私は関数列車に乗りましたが、遅延言語や優れたラムダ構文を持っているのであれば、それさえも必要ないので、純粋に関数型スタイルではマクロはそれほど役に立たないと考えています。
そこでお勧めします 実用的な Common Lisp そして Lisp について. 。PLT スキームを使用したい場合は、ほとんどの場合、 defmacro
マクロは動作します define-macro
. 。あるいは単に Common Lisp を使用してください。
他のヒント
マクロは、新しい制御構造と新しいバインディング構造を実装するために必要です。
したがって、 http://planet.plt-scheme.org でこれらの種類の構成要素を探します。 PLaneTでは、ドキュメントとコードの両方を参照します。
新しい制御構造の例:
http://planet.plt-scheme.org/package-source/soegaard/control.plt/2/0/planet-docs/manual/index.html
新しいバインディングフォームの例を見つけるには、<!> quot; with-<!> quot;で始まるマクロを探します。 有用な例の1つは、PLaneTのmath.pltにもあります。
; Within a (with-modulus n form1 ...) the return values of
; the arithmetival operations +, -, * and ^ are automatically
; reduced modulo n. Furthermore (mod x)=(modulo x n) and
; (inv x)=(inverse x n).
; Example: (with-modulus 3 (^ 2 4)) ==> 1
(define-syntax (with-modulus stx)
(syntax-case stx ()
[(with-modulus e form ...)
(with-syntax ([+ (datum->syntax-object (syntax with-modulus) '+)]
[- (datum->syntax-object (syntax with-modulus) '-)]
[* (datum->syntax-object (syntax with-modulus) '*)]
[^ (datum->syntax-object (syntax with-modulus) '^)]
[mod (datum->syntax-object (syntax with-modulus) 'mod)]
[inv (datum->syntax-object (syntax with-modulus) 'inv)])
(syntax (let* ([n e]
[mod (lambda (x) (modulo x n))]
[inv (lambda (x) (inverse x n))]
[+ (compose mod +)]
[- (compose mod -)]
[* (compose mod *)]
[square (lambda (x) (* x x))]
[^ (rec ^ (lambda (a b)
(cond
[(= b 0) 1]
[(even? b) (square (^ a (/ b 2)))]
[else (* a (^ a (sub1 b)))])))])
form ...)))]))
最後の質問に答え始めます。関数の代わりにマクロを使用する場合。マクロは関数ができないことを行い、関数はマクロができないことを行います。したがって、それらを混ぜることは困難になりますが、さらに深くしましょう。
引数を評価する場合は関数を使用し、引数を評価しない場合はマクロを使用します。それはあまり有用ではありませんか?マクロを使用するのは、別の方法で何かを書きたいとき、パターンを見て抽象化したいときです。たとえば、fooのさまざまな値に対して、fooのみが変更され、fooのみが変更されたfoo-create、foo-process、およびfoo-destroyという3つの関数を定義します。パターンはありますが、関数には高すぎるため、マクロを作成します。
私の謙虚な経験では、Schemeのマクロは、Common Lispや Clojure など、他のLispと同じように使用されます。衛生的なマクロはそれほど良いアイデアではないかもしれないという証拠だと思いますが、ここではなぜポール・グラハムに反対します。汚れている(衛生的でない)場合があるからではなく、衛生的なマクロが複雑になるか複雑になるためです。
Peter SeibelによるPractical Common Lispには、マクロの入門書があります。 Paul GrahamによるLispでは、より複雑な例の良い情報源になるかもしれません。また、たとえばCommon Lispの組み込みマクロを見てください。
マクロ経由のオートマトン論文では、Schemeのマクロを介して有限状態マシンを実装するための関数型プログラミングの真珠を紹介しています。
本 The Reasoned Schemer は、本で使用されている論理プログラミング言語であるminiKanrenの完全なマクロベースの実装。 このペーパーは、ミニカンレンとその実装を、本よりも形式的かつ簡潔に示しています。
ラムダ形式ではない、より高度なマクロの例は、Common Lispのマクロ with-slots です。これにより、オブジェクトスロットアクセスが通常の変数アクセスのように見えます。
(with-slots (state door) car
(when (eq state :stopped)
(setq state :driving-around)
(setq door :closed)))
これは、 with-slots を使用するとスロットをSETQ経由で変更し、外部の変更をすぐに確認できるため、スロット値をローカル変数にバインドしてアクセスすることとは異なります。
p>手のひらで多くのスキームを実行していたときにcurry
マクロがありました。とても便利でした。
Schemeマクロを使用すると、元の言語の作成者が自分で含めなかった機能を追加できます。それがマクロの背後にある哲学全体です。
小さな例を次に示します。PLTSchemeは、スライドショーと呼ばれるプレゼンテーションを作成するための言語を提供します。マクロを使用してスライド番号をスライドに関連付け、より簡単に管理できるようにしました。
I <!>#8217;中置構文を提供するマクロを作成しました。派手すぎるものはありません。優先順位なし。 I <!>#8217; mは一般に接頭辞構文で問題ありませんが、<!> lt;の場合は中置記号を使用します。および<!> gt;。
手順が不十分な場合に使用します。