compiler-construction - 方案中的匿名宏

标签 compiler-construction macros functional-programming lisp scheme

我最近在学习 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 视为不同的类型,第二种可能更优雅。

我的问题是:

  1. define-macro 有什么作用?
  2. 宏和 lambda 之间的根本区别是什么?
  3. 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/

相关文章:

qt - 如何使编译器检查给SIGNAL()的内容?

c - 在宏中使用枚举整数值来格式化字符串

haskell - 删除 haskell 语句中的括号

haskell - 如何在函数式编程中增加变量?

c# - 如何在 roslyn 中使用 Formatter.Format(SyntaxNode,Workspace)?

c - 为什么 C 编译器不检查枚举?

c - 用于指定 C 枚举大小的 GCC/Clang/MSVC 扩展?

java - 运行时错误。请让我理解我做错了什么

macros - 在 Rust 的过程宏中使用 $crate?

Java8 FP if/else if/else 替换为 lambdas