我最近在学习 scheme 并且对没有标识符就无法评估宏的设计感到好奇,而 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中是否有匿名宏,如果没有,为什么?
最佳答案
首先是一个如何模拟“匿名宏”的例子。 然后我会评论有用性。
考虑这个匿名宏转换器, 它采用表示数字的语法对象 并返回一个新的语法对象表示 输入数字的两倍。
(λ (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 中进行了测试。
关于compiler-construction - 方案中的匿名宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14671061/