9

MITスキームでこの些細な(Common Lispの)マクロに相当するものを作成しようとすると困惑します:

(defmacro funcify (exp)
    `(lambda (x) ,exp))

これは、2回目のSICP講義で構築された関数に基づく数値方程式ソルバーである、単純な個人プロジェクト用です。このマクロが「安全」または「衛生的」でないことや、expが'x以外の記号を参照している場合に変数をキャプチャすることは気にしません。書けるようになりたい

(solv '(* 60 x) '(* 90 (- x 1)))

ここで、solvは次のとおりです。

(define (solv lh-exp rh-exp)
    (solve (funcify lh-exp) (funcify rh-exp)))

入力する代わりに

(solve (lambda (x) (* 60 x)) (lambda (x) (* 90 (- x 1))))

しかし、MITスキームの構文規則を使用してこれを行う方法を理解することはできません。

私はこれを試しましたが、機能しません:

(define-syntax funcify
  (syntax-rules ()
    ((funcify y) (lambda (x) y))))
;Value: funcify

(funcify x)
;Value 17: #[compound-procedure 17]

((funcify x) 10)
;Unbound variable: x

私はおそらく言及する価値のない他のことを試みましevalたが、役に立たなかったのです。

また、Schemeのマクロシステムに関する優れたチュートリアル(参照ではない)への参照は、小さな簡単な例から始まり、十分な解説付きで構築され、特にバッククォート-コンマスタイルのLISPマクロ(私にとっては非常に直感的です)をに変換する方法を示していますスキームの構文マクロシステムは素晴らしいでしょう。

4

2 に答える 2

7

ではできませんsyntax-rules。話の終わり。

x出力式に任意の識別子 (この場合は ) を挿入するには、衛生状態を破る必要があり、衛生状態syntax-rulesを破る手段はありません。これを行うには、下位レベルのマクロ システムを使用する必要があります。MIT スキームは明示的な名前変更を使用します (Matthias Benkard の回答を参照) が、を使用する他のスキームの実装ではsyntax-case、次のように行うことができます。

(define-syntax funcify
  (lambda (stx)
    (syntax-case stx ()
      ((_ body)
       (with-syntax ((x (datum->syntax stx 'x)))
         #'(lambda (x)
             body))))))

キーは、あたかも呼び出しの構文コンテキストにあるかのように(datum->syntax stx 'x)シンボルを挿入するビットです。xfuncify

ちなみに、 yoursolvもプロシージャではなくマクロである必要がありますが、少なくともsyntax-rulesマクロにすることができます。

(define-syntax solv
  (syntax-rules ()
    ((_ lhs rhs) (solve (funcify lhs) (funcify rhs)))))
于 2011-10-12T17:44:11.720 に答える
4

明示的な名前変更マクロdefmacroを使用することで、基本的に と同じことができます。唯一の重要な違いは、入力フォームを自分で分解する必要があることです。

(define-syntax funcify
  (er-macro-transformer
    (lambda (form rename cmp)
      (let ((exp (cadr form)))
        `(,(rename 'lambda) (x) ,exp)))))
于 2011-10-12T17:52:49.097 に答える