【问题标题】:Anonymous macro in scheme方案中的匿名宏
【发布时间】:2013-01-18 05:26:59
【问题描述】:
我最近在学习方案,并对没有标识符无法评估宏的设计感到好奇,而 lambda(procedure) 可以这样做。
例如,我可以像这样使用匿名 lambda:
((lambda x x) 1 2 3)
似乎我必须使用以下语法定义宏:
(define-macro my-macro (lambda x x))
我很好奇为什么会有这样的方法直接像这样创建一个宏:
(define my-macro (macro-lambda x x))
我想如果将宏和 lambda 视为不同的类型,第二个可能会更优雅。
我的问题是:
-
define-macro 是做什么的?
- 宏和 lambda 之间的根本区别是什么?
- scheme 中是否有匿名宏,如果没有,为什么?
【问题讨论】:
标签:
compiler-construction
macros
functional-programming
lisp
scheme
【解决方案1】:
首先是一个如何模拟“匿名宏”的示例。
然后我将评论有用性。
考虑这个匿名宏转换器,
接受一个表示数字的语法对象
并返回一个新的语法对象,表示
输入数字的两倍。
(λ (stx)
(datum->syntax stx
(* 2 (syntax->datum stx))))
我们可以这样测试:
> ((λ (stx)
(datum->syntax stx
(* 2 (syntax->datum stx))))
#'3)
结果是一个带有 6 的语法对象。
如果我们想要实际的数字 6,我们可以使用eval。
> (eval ((λ (stx)
(datum->syntax stx
(* 2 (syntax->datum stx))))
#'3))
6
现在我们已经使用匿名语法转换器来重写
3变成6。
匿名宏有用吗?
匿名函数用于函数的地方,
但你只需要一次。如果相同的匿名函数是
在一个程序中使用了两次,最好给它一个名字,
然后只需参考它两次。
语法转换也是如此。如果您需要
至少两次相同的转换,你应该给它一个名字。
唯一一次匿名语法转换是有意义的
是,如果它只使用一次。在大多数情况下,它会更简单
只是为了写转换的结果。我想不出来
的一个例子,一个匿名的转换会
事情更简单。
注意:所有示例都在 Racket 中进行了测试。
【解决方案2】:
宏在编译时转换树,而其余代码在运行时执行。
一般来说,两种操作(宏扩展和 lisp 代码执行)都是处理列表的过程。 IE。对于宏和过程,lambda 没有根本区别,只是它们执行的时间。这意味着会出现一些其他问题,例如命名等。
(define ..) 在运行时执行,所以我认为你的建议不会真正起作用。
因此,defmacro 语法清楚地表明宏是一个普通函数,但在编译时进行评估。宏 lambda 宁愿掩盖这一点。