マクロ展開には副作用がありますか (またはすべきですか)? たとえば、コンパイル時に実際に Web ページのコンテンツを取得するマクロを次に示します。
#lang racket
(require (for-syntax net/url))
(require (for-syntax racket/port))
(define-syntax foo
(lambda (syntx)
(datum->syntax #'lex
(port->string
(get-pure-port
(string->url
(car (cdr (syntax->datum syntx)))))))))
その後、私は行うことができ(foo "http://www.pointlesssites.com/")
、それはに置き換えられます"\r\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\r\n\t <and so on>"
これは良い習慣ですか?Racket がこのコードを 1 回だけ実行することを保証しますか? マクロに行を追加する(display "running...")
と、一度だけ出力されますが、1 つの例から一般化するのは嫌です...
追伸 - 私が尋ねている理由は、実際にこれが時々本当に役立つと思うからです. たとえば、これは、(コンパイル時に) Google API Discovery サービスからディスカバリー ドキュメントをロードし、そのラッパーを自動的に作成できるライブラリです。ライブラリがローカル ファイルからではなく、実際に Web からディスカバリー ドキュメントをフェッチするようになれば、本当にすばらしいと思います。
また、別の種類の副作用を持つマクロの例を挙げると、Racket の小さなサブセットを (eta 拡張された) ラムダ計算 (もちろん、Racket で実行可能) に変換するマクロを作成したことがあります。マクロが関数の変換を終了するたびに、その結果を辞書に格納して、後でマクロを呼び出したときにその関数定義を独自の変換で使用できるようにします。