什么时候使用with-syntax
在用syntax-case的时候,多处使用quasisyntax,unsyntax,unsyntax-splicing会把代码搞的跟咒语一样:
;无法嘲笑perl了
(syntax-case #'(a 1 2 3) ()
[(name . args) #`(name #,@#'args)]
(syntax-case #'(a 1 2 3) ()
[(name . args) #`(name #,@#'args)]
这个时候with-syntax就又用了,能让代码可读性好很多:
;又可以嘲笑perl了
(syntax-case #'(a 1 2 3) ()
[(name . args)
(with-syntax ([(a ...) #'args])
#'(name a ...))])
(syntax-case #'(a 1 2 3) ()
[(name . args)
(with-syntax ([(a ...) #'args])
#'(name a ...))])
宏的模板部分就简单多了
with-syntax语法跟let类似,但是自带模式匹配,跟match-let更像
前面那个例子太trival了,下面来个稍微现实一点的:
比如我想要个新语法alist ,它根据所给的参数生成一个asscociative list: (即变量及其值的二元组 list)
(let ([a "meme"])
(alist a (b 1) (c (* 2 b))))
(alist a (b 1) (c (* 2 b))))
=> {{a "meme"} {b 1} {c 2}}
在这个环境下,a的值是字符串"meme",b的值是1,c是2,所以生成对应的alist:{{a "meme"} {b 1} {c 2}}
(define-syntax alist;(alist arg ...)
(lambda (x)
(define (x->name&value x);aux transformer function
(syntax-case x ()
[(n v) (identifier? #'n) #'(n v)];(var val) -> (var val)
[n (identifier? #'n) #'(n n)])) ;var -> (var val)
(syntax-case x ()
[(alist arg ...)
(with-syntax
([((name value) ...)
(map x->name&value #'(arg ...))])
#'(let* ([name value] ...)
(list (list 'name name) ...)))])))
(lambda (x)
(define (x->name&value x);aux transformer function
(syntax-case x ()
[(n v) (identifier? #'n) #'(n v)];(var val) -> (var val)
[n (identifier? #'n) #'(n n)])) ;var -> (var val)
(syntax-case x ()
[(alist arg ...)
(with-syntax
([((name value) ...)
(map x->name&value #'(arg ...))])
#'(let* ([name value] ...)
(list (list 'name name) ...)))])))
这里使用with-syntax可以避免分情况讨论,分情况的细节封装在辅助transformer,然后map过去就是了.这样一来可读性提高了不少.嗯哼