macros - 为什么 foo 与这个 Racket 宏中的 (foo) 具有相同的值?

标签 macros racket read-eval-print-loop

我正在尝试理解 Racket 环境中的宏。这个概念让我很感兴趣。

在 Dr. Racket 的定义窗口上写下这个定义后:

(define-syntax foo
    (lambda (stx)
      (syntax "I am foo")))

我使用 REPL 调用了以下表达式:

> foo
"I am foo"

> (foo)
"I am foo"

这些结果让我感到惊讶。对于 foo 的第一次调用,我期待类似 #procedure 的东西。

为什么 (foo) 和 foo 提供相同的输出?

通常,我在 Racket 中添加括号时非常小心。通常,它们会完全改变被调用表达式的含义。在这种情况下,显然没有任何区别。

提前致谢。

最佳答案

Usually, I am pretty careful about adding parenthesis in Racket.

是的,你要小心是对的。它通常会产生影响。

然而,在您的情况下,它似乎没有什么区别,因为您正在创建一个过于简单的宏,无论宏是作为常规转换器还是作为 identifier macro 调用,它的扩展方式都是一样的。 .

I was expecting something like a #procedure for the first call on foo.

我想先解决这个问题。宏在句法上改变你的程序。例如,我可以编写一个宏 flip 来翻转操作数,这样

(flip foo 1 (let) bar baz 2)

扩展(不是评估)到:

(2 baz bar (let) 1 foo)

再次,我想强调的是,这是一种程序转换,就像您如何使用编辑器编辑代码一样。

现在,让我们编写一些实际的宏:

(define-syntax bar
  (lambda (stx)
    (cond
      [(equal? (syntax->datum stx) '(bar abc def)) #'(+ 1 1)]
      [else #'(+ 2 2)])))

(bar abc def)      ;== expands => (+ 1 1) == evaluates => 2
(bar 42 (abc) qqq) ;== expands => (+ 2 2) == evaluates => 4
(bar)              ;== expands => (+ 2 2) == evaluates => 4

在上面的宏中,它检查输入语法在句法上是否为(bar abc def)。如果是,它将转换为 (+ 1 1)。否则,它转换为 (+ 2 2)

所有这些都是为了向您表明,期望宏产生“#procedure”是不合理的(当然,除非宏扩展为 lambda),因为宏所做的是转换语法。它不会创建过程。

最后的谜团是裸露的 foo 发生了什么。让我们创建一个宏 baz 来理解这一点:

(define-syntax baz
  (lambda (stx)
    (cond
      [(equal? (syntax->datum stx) 'baz) #'1]
      [(equal? (syntax->datum stx) '(baz)) #'2]
      [else #'3])))

baz      ;== expands => 1
(baz)    ;== expands => 2
(baz 10) ;== expands => 3

事实证明,一个裸标识符也可以是一个宏!

现在,考虑您的 foo:

(define-syntax foo
    (lambda (stx)
      (syntax "I am foo")))

这是一个忽略其操作数的转换,并且总是扩展为 "I am foo"

所以:

(foo 1 2 3) ;== expands => "I am foo"
(foo x y z) ;== expands => "I am foo"
(foo)       ;== expands => "I am foo"
foo         ;== expands => "I am foo"

请注意,在大多数宏中,我们使用模式匹配来提取操作数。当输入语法不匹配任何模式时,模式匹配会引发语法错误。例如,这允许我们创建一个不允许将其用作标识符宏的宏。

(define-syntax food
  (lambda (stx)
    (syntax-case stx ()
      ;; match when there is a parenthesis around the macro
      [(_ ...) #'1])))

(food) ;=> 1
food   ;=> food: bad syntax

关于macros - 为什么 foo 与这个 Racket 宏中的 (foo) 具有相同的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66726427/

相关文章:

qt - Qt : what do they do? 中的 SIGNAL 和 SLOT 宏

android - 何时在 Android NDK 中使用 JNIEXPORT 和 JNICALL?

html - Racket : How do i print the mysql result in a HTML page

scala - 是否可以记录 Scala REPL 的输出?

macros - Scheme宏中的任意计算

macros - 带有参数 x 和输出 $x 和 @x 的宏

scheme - 方案中嵌套定义的体面方式

module - ( Racket ) "Cannot reference an identifier before its definition"带有从模块导入的标识符

emacs - Emacs 启动 Repl 时出错

javascript - emacs缓冲区中的node.js没有进程——更好的系统在emacs中交互式执行js