2011-07-27 11 views
1

間でマクロを使用して、私は変更可能な構造体のフィールドをインクリメントするマクロを作成する方法について設定します。ラケット:自分自身のラケットでは、より高度なマクロを教えるためには、モジュール

(increment! instance name field)

=>

(set-name-field instance (get-name-field instance))

私はそのマクロを作成しました複数のモジュール間で共有することが有効であると判断しました。残念ながら、構造体のミューテータはマクロを定義するモジュールの範囲にないため、拡張エラーが発生します。

次は、この問題を示す意図した例です。私は知りたいです:

  1. 私は慣用ラケットスタイルでマクロコードを書いていますか?これは正しいアプローチですか?

  2. マクロの展開を制御して、それが元のコンテキストにない識別子の存在下で動作するようにするにはどうすればよいですか?

ありがとう。

#lang racket/load 

(module util racket 

    (define-syntax increment! 
    (lambda (stx) 
     (syntax-case stx() 
     [(increment! s sn fn i) 
     (with-syntax 
      ([set! (string->symbol 
        (format "set-~a-~a!" (syntax-e #'sn) (syntax-e #'fn)))] 
       [get (string->symbol 
        (format "~a-~a" (syntax-e #'sn) (syntax-e #'fn)))]) 
      #'(set! s (+ i (get s))))] 
     ;; default increment of 1 
     [(increment! s sn fn) #'(increment! s sn fn 1)]))) 

    (provide increment!) 
) 

(module bank racket 
    (require 'util) 
    (struct money (dollars pounds euros) #:mutable #:transparent) 

    (let ([m (money 0 50 20)]) 
    (increment! m money pounds 100) 
    (increment! m money dollars) 
    m) 
) 

(require 'bank) 

の業績は拡大:設定マネー・ポンド:内のモジュールで結合していない識別子を!

答えて

3

あなたはそれだけではできません。問題は正しい名前のシンボルを生成しているにもかかわらず、そのままの状態でシンボルを返すことです。つまり、with-syntaxはデフォルトの(そして間違った)字句コンテキストを与えます。代わりに、datum->syntaxを使用して、正しいコンテキストを与える必要があります。

以下は、期待どおりに動作するコードのリビジョンです。それについてもっと見るには、私の最近のblog postで非衛生的なマクロのテーマをご覧ください。

ただし、これは堅牢なソリューションではありません。セッターとゲッターの名前が異なるとどうなりますか?より強固な解決策は、構造体名を使用して、その中から正しい情報を抽出することです(構文時に、マクロ内で)。詳細はthe manualを参照してください。 mailing listに質問をすることは良いことです。あなたが望むものを得るためのより良い方法があるかもしれないし、ドット表記のような機能を探しているなら、より良い解決策かもしれないからです。

#lang racket/load 

(module util racket 
    (define-syntax increment! 
    (lambda (stx) 
     (syntax-case stx() 
     [(increment! s sn fn i) 
     (let ([id (lambda (fmt) 
        (let ([str (format fmt (syntax-e #'sn) (syntax-e #'fn))]) 
         (datum->syntax #'sn (string->symbol str))))]) 
      (with-syntax ([set! (id "set-~a-~a!")] 
         [get (id "~a-~a")]) 
      #'(set! s (+ i (get s)))))] 
     ;; default increment of 1 
     [(increment! s sn fn) #'(increment! s sn fn 1)]))) 
    (provide increment!)) 

(module bank racket 
    (require 'util) 
    (struct money (dollars pounds euros) #:mutable #:transparent) 
    (let ([m (money 0 50 20)]) 
    (increment! m money pounds 100) 
    (increment! m money dollars) 
    m)) 

(require 'bank) 
+0

ありがとう@Eli Barzilay、文脈を注入すると非常に優雅に動作します。私は解決策がかなり堅牢ではないことに同意する、私は最終的に構文 - ケースを学ぶために良い言い訳としてそれを単にラッチした。私は確かにstruct-infoを使って改良しようとします。 – LazyBitStream

関連する問題