这个R5RS宏是我尝试过的,几乎就是我想做的事情。 Racket或其他实现并不喜欢这个宏我想要魔术发生的地方。
(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并考虑is-eqv的实现?会指出我在正确的方向,但它似乎不是在那里定义的宏。
如果在R5RS编译时间不可能,那么如何用R6RS完成?
答案 0 :(得分:3)
Chris Jester-Young答案的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之后不会标准化的程序宏或宏设施之前,应该三思而后行。
答案 1 :(得分: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
的方法要简单得多(此实现使用Racket的自定义哈希表):
(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))))