【问题标题】: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 视为不同的类型,第二个可能会更优雅。

我的问题是:

  1. define-macro 是做什么的?
  2. 宏和 lambda 之间的根本区别是什么?
  3. 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 宁愿掩盖这一点。

      【讨论】:

        猜你喜欢
        • 2018-07-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多