2013-06-12 43 views
1

這個R5RS宏是我嘗試過的,幾乎是我想要做的。球拍或其他實現不喜歡這個宏恰好在我想要發生魔法的地方。是否可以匹配R5RS宏定義中的重複模式define-syntax/syntax-rules?

(define-syntax quote-unique 
    (syntax-rules (magic end) 

    ;; end case 
    ((quote-unique magic processed end) 
    'processed) 

    ;; finished iteration 
    ((quote-unique magic (processed ...) sym1 end rest ...) 
    (quote-unique magic (processed ... sym1) rest ... end)) 

    ;; match (doesn't work since racket doesn't like sym1 twice in template) 
    ;; but I'm looking for the same expression twice 
    ((quote-unique magic processed sym1 sym1 . rest) 
    (quote-unique magic processed sym1 . rest)) 

    ;; rotate 
    ((quote-unique magic processed sym1 sym2 rest ...) 
    (quote-unique magic processed sym1 rest ... sym2)) 

    ;; start iteration 
    ((quote-unique rest ...) 
    (quote-unique magic() rest ... end)))) 

這Common Lisp中是很容易:

(defmacro quote-unique (&rest xs) 
    (labels ((remove-duplicates (lis) 
     (if lis 
     (if (member (car lis) (cdr lis)) 
       (remove-duplicates (cdr lis)) 
      (cons (car lis) (remove-duplicates (cdr lis))))))) 

    (list 'quote (remove-duplicates xs)))) 

我也一直在讀Define syntax primer和思考的實施,當量?會讓我指出正確的方向,但它似乎並不是在那裏定義的宏觀。

如果在R5RS編譯時不可能,那麼R6RS怎麼能這樣做呢?

回答

2

您不能使用syntax-rules來完成此操作,但是您可以使用syntax-case來完成此操作,方法是使用使用free-identifier=?的警衛。這裏有一個例子:

(define-syntax (remove-id stx) 
    (syntax-case stx() 
    ((_ head()) 
    #''()) 
    ((_ head (next tail ...)) (free-identifier=? #'head #'next) 
    #'(remove-id head (tail ...))) 
    ((_ head (next tail ...)) 
    #'(cons 'next (remove-id head (tail ...)))))) 

> (remove-id foo (foo bar baz qux foo bar)) 
; => (bar baz qux bar) 

不過,當然,如果你要使用syntax-case,還有一個更簡單的實現你quote-unique(該實現使用球拍的自定義哈希表)的方式:

(require (for-syntax racket/dict)) 
(define-syntax (quote-unique stx) 
    (define (id-dict ids) 
    (foldl (lambda (id d) 
      (dict-set d id #t)) 
      (make-immutable-custom-hash free-identifier=? (compose eq-hash-code syntax-e)) 
      (syntax-e ids))) 
    (syntax-case stx() 
    ((_ ids ...) 
    (with-syntax ((unique (dict-keys (id-dict #'(ids ...))))) 
     #''unique)))) 
3

的克里斯小丑,年輕的回答remove-id例子是表達在R5RS:

(define-syntax remove-id 
    (syntax-rules() 
    ((remove-id s (t ...)) 
    (letrec-syntax ((aux (syntax-rules (s) 
          ((aux p*()) 
          'p*) 
          ((aux p* (s . rest)) 
          (aux p* rest)) 
          ((aux (p (... ...)) (u . rest)) 
          (aux (p (... ...) u) rest))))) 
     (aux() (t ...)))))) 

(請注意,由引用省略號並不嚴格R5RS(僅R7RS),但僅用於按給定順序生成結果序列,而不是反轉。因此,通過添加另一個宏,你甚至可以省略省略號。)

我希望這個例子清楚地說明如何解決你原來的問題。如果某些東西可以用衛生宏來解決,那麼在使用R6RS之後可能不會標準化的程序宏或宏設施之前,應該先考慮一下。