许多宏的例子似乎都是关于隐藏lambda,例如在CL中使用open-file.我正在寻找一些更奇特的宏用途,特别是在PLT Scheme中.我想了解何时考虑使用宏与使用函数.
需要宏来实现新的控制结构和新的绑定结构.
因此,请在http://planet.plt-scheme.org上查找这些类型的结构.在PLaneT,您可以浏览文档和代码.
新控制结构的示例:
http://planet.plt-scheme.org/package-source/soegaard/control.plt/2/0/planet-docs/manual/index.html
要查找新绑定表单的示例,请查找以"with-"开头的宏.一个有用的例子也可以在PLaneT的math.plt中找到.
; Within a (with-modulus n form1 ...) the return values of ; the arithmetival operations +, -, * and ^ are automatically ; reduced modulo n. Furthermore (mod x)=(modulo x n) and ; (inv x)=(inverse x n). ; Example: (with-modulus 3 (^ 2 4)) ==> 1 (define-syntax (with-modulus stx) (syntax-case stx () [(with-modulus e form ...) (with-syntax ([+ (datum->syntax-object (syntax with-modulus) '+)] [- (datum->syntax-object (syntax with-modulus) '-)] [* (datum->syntax-object (syntax with-modulus) '*)] [^ (datum->syntax-object (syntax with-modulus) '^)] [mod (datum->syntax-object (syntax with-modulus) 'mod)] [inv (datum->syntax-object (syntax with-modulus) 'inv)]) (syntax (let* ([n e] [mod (lambda (x) (modulo x n))] [inv (lambda (x) (inverse x n))] [+ (compose mod +)] [- (compose mod -)] [* (compose mod *)] [square (lambda (x) (* x x))] [^ (rec ^ (lambda (a b) (cond [(= b 0) 1] [(even? b) (square (^ a (/ b 2)))] [else (* a (^ a (sub1 b)))])))]) form ...)))]))
我将开始回答最后一个问题.何时使用宏而不是函数.宏做功能不能做的事情,功能做宏不能做的事情,所以很难混合它们,但让我们更深入.
如果希望参数被评估,则可以使用函数;如果希望参数未被评估,则可以使用宏.这不是很有用,是吗?当您想要以不同的方式编写内容时,当您看到模式并且想要抽象时,可以使用宏.例如:我为foo的不同值定义了三个函数foo-create,foo-process和foo-destroy,并且使用类似的主体,其中唯一的变化是foo.有一个模式,但功能太高,所以你创建一个宏.
在我不起眼的经历中,Scheme中的宏与其他Lisp一样多,比如Common Lisp或Clojure.我想这可能证明卫生宏可能不是一个好主意,在这里我不同意保罗格雷厄姆的原因.这不是因为有时候你想要变脏(不卫生),而是因为卫生的宏最终变得复杂或错综复杂.
我只使用Scheme宏(define-syntax
)来处理像lambda语法更好的小事情:
(define-syntax [: x] (syntax-case x () ([src-: e es ...] (syntax-case (datum->syntax-object #'src-: '_) () (_ #'(lambda (_) (e es ...)))))))
哪个让你写
[: / _ 2] ; <-- much better than (lambda (x) (/ x 2))
Dan Friedman使用宏来实现OO的令人费解的实现:http://www.cs.indiana.edu/~dfried/ooo.pdf
但老实说,我所定义的所有有用的宏都是从Paul Graham的On Lisp中偷来的,并且通常更容易编写defmacro
(define-macro
在PLT Scheme中).例如,aif
非常难看define-syntax
.
(define-syntax (aif x) (syntax-case x () [(src-aif test then else) (syntax-case (datum->syntax-object (syntax src-aif) '_) () [_ (syntax (let ([_ test]) (if (and _ (not (null? _))) then else)))])]))
define-syntax
很奇怪,它只是很容易用于非常简单的宏,你很高兴无法捕获变量; 非常复杂的宏DSL,你很高兴无法轻易捕获变量.在第一种情况下,你想要编写代码而不考虑它,在第二种情况下你已经充分考虑了DSL,你愿意用syntax-rules
/ syntax-case
语言写一部分它不是Scheme,以避免神秘的错误.
但我不会在Scheme中使用那么多的宏.惯用方案非常实用,很多时候你只想写一个功能程序,然后隐藏一些lambda.我上了功能列车,现在相信如果你有一个懒惰的语言或一个良好的lambda语法,即使这是没有必要的,所以宏在纯函数风格中并不是那么有用.
所以我推荐Practical Common Lisp和On Lisp.如果你想使用PLT Scheme,我认为他们的大多数defmacro
宏都可以使用define-macro
.或者只使用Common Lisp.