我最近正在学习计划并对设计感到好奇,因为没有标识符就无法评估宏,而lambda(程序)可以这样做。
例如,我可以使用匿名lambda:
((lambda x x) 1 2 3)
似乎我必须使用以下语法定义宏:
(define-macro my-macro (lambda x x))
我很好奇为什么这样的方法会像这样直接创建一个宏:
(define my-macro (macro-lambda x x))
我想如果将宏和lambda视为不同的类型,第二个可能更优雅。
我的问题是:
define-macro
做什么?答案 0 :(得分:5)
首先举例说明如何模拟"匿名宏"。 然后我会对有用性发表评论。
考虑这个匿名宏变换器, 它采用表示数字的语法对象 并返回一个新的语法对象表示 输入数字的两倍。
(λ (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中进行了测试。
答案 1 :(得分:0)
宏在编译时转换树,而其余代码在运行时执行。
通常,两个操作(宏扩展和lisp代码执行)都是在列表上工作的过程。即对于宏和程序,lambda没有根本的区别,它只是执行它们的时间。这意味着会出现一些其他问题,例如命名等。
(define ..)在运行时执行,因此我认为你的建议不会真正起作用。
因此,defmacro语法清楚地表明宏是一个普通函数,但在编译时进行了评估。 macro-lambda宁愿暗示这一点。