macros - (mymacro arg) 和 (eval (myfunc (quote arg))) 有什么区别

标签 macros lisp eval

我在 Lisp 中“查看”宏的方式如下:每当我看到宏调用 (mymacro arg1 arg2 ... argn) 时,我认为它与 ( 相同eval (myfun (quote arg1) (quote arg2) ... (quote argn))),其中 myfun 是一个函数,其主体与 mymacro.I 的主体完全相同想象一下这是一种过于简单化的理解宏的方式。但我很难找到失败的例子。

那么,是否有 s 表达式 BODY 和 ARG 的示例,使得给定以下 mymacromyfun 定义,

(defmacro mymacro (param) BODY) 
(defun    myfun   (param) BODY)

表达式 (mymacro ARG)(eval (myfun (quote ARG))) 评估出相同的结果吗?

PS:我只使用一个参数,因此写这个问题更容易,但我显然对具有多个参数的示例感到满意。

PS:我对最后的语义差异更感兴趣,而不是实现细节、性能差异等。

最佳答案

But I'm having trouble finding an example where it fails.

(defmacro plus-mac (left right)
  `(+ ,left ,right))

(defun plus-expander (left right)
  `(+ ,left ,right))

然后:

(let ((a 3) (b 4))
  (plus-mac a b))  ;; -> 7, works!

(let ((a 3) (b 4))
  (eval (plus-expander 'a 'b))) ;; fail: variables a and b not defined

您在某处读到过类似“宏被替换为在其位置上求值的代码(由其扩展器函数生成)”的宏描述,并且过于字面理解了它。

宏被替换,但扩展不被评估; eval 调用未插入到代码中的该位置。

首先,宏通常在代码执行之前展开。这两个 Action 可以完全分开。例如,宏可能会在开发人员的构建计算机上展开,而评估则在程序在用户的目标计算机上运行时进行。

即使在计算表达式之前立即展开宏,该计算也不是通过插入代码中的 eval 调用来完成的。正如我上面的示例所示,这不能正确地与词法作用域配合使用。

最后,宏(我们正在讨论的不卫生的、Common-Lisp 风格的宏,它们执行简单的替换)并不像问题中想象的那样在幕后工作。像 (mac a b (c d (e))) 这样的宏调用会导致调用扩展器函数。该函数有两个参数:整个宏形式和宏时间环境。将宏语法分为参数 abcdedefmacro 编写的代码完成。扩展器看起来像:

(lambda (form env)
  (destructuring-bind (#:operator a b (c d (e))) form
    ... body goes here ...))

这仍然不准确,因为 destructuring-bind 不会产生良好的诊断。解构 lambda 列表和宏 lambda 列表类似,但不相同。这仅用于说明目的,以表明 defmacro 在宏主体周围插入解构代码;该代码通过一个参数接收整个宏调用形式,并设置保存命名片段的局部变量。

如果您想了解幕后情况,请尝试展开 defmacro 调用以查看它生成的代码:

(macroexpand '(defmacro mac (a b (c d (e))) (list a b c d e)))

关于macros - (mymacro arg) 和 (eval (myfunc (quote arg))) 有什么区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77090618/

相关文章:

multithreading - lisp 图像中基于 hunchentoot 的应用程序(来自 buildapp)立即返回

python - 如何将 eval() 函数与变量列表一起使用?

c - 使用循环定义的宏

shell - 首先使用来自文件的输入运行交互式 REPL,然后使用用户输入运行交互式 REPL

macros - 在运行时处理内部变量和数据结构的 LISP 宏

c# - 如何评估 C# 中可以被零除的字符串表达式?

Javascript 循环从数组中获取动态变量(和值),无需 eval

printing - 有什么方法可以使用Google Apps脚本打印Google表格工作表?

c - operator++ 应用两次,具体取决于#define 函数的参数

macros - 在 Julia 中,如何显示宏的内容?