2011-07-27 76 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