【问题标题】:Why is the return value of a function not evaluated but the return value of a macro is?为什么不计算函数的返回值而宏的返回值是?
【发布时间】:2016-11-08 15:08:11
【问题描述】:

加一加一的函数:

(defn one-plus-one [] (list + 1 1))

调用时返回:

(#object[clojure.core$_PLUS_ 0x47fa7bd5 "clojure.core$_PLUS_@47fa7bd5"] 1 1)

同样的函数体包裹在一个宏中:

(defmacro one-plus-one [] (list + 1 1))

调用时返回:

2

为什么 Clojure 期望宏返回可以计算的表达式?

编辑

the possible duplicate question 的答案告诉我们宏与函数有何不同。但没有回答为什么。打个比方,我知道从高处留下的物体垂直落下撞击地面。我的问题是为什么它垂直下降?

【问题讨论】:

  • 我猜你应该阅读更多关于宏的信息。您可以将宏调用视为在编译时用宏的内容替换自身的代码。因此,对于宏一加一,您可以想象 (one-plus-one)(+ 1 1) 放入您的源代码中,然后将其与源代码的其余部分一起评估。
  • 重新编辑,引用linked question,函数转换值,宏将代码转换成其他代码。
  • 您的函数示例只是返回一个列表结构,这就是您定义它要做的事情。您的宏扩展为代码 (+ 1 1),当该代码被评估时,结果为 2。您可以通过运行 (macroexpand '(one-plus-one)) 查看中间代码。
  • “为什么 Clojure 期望宏返回可以计算的表达式?”因为这就是拥有宏的意义所在。您的问题听起来好像在问“为什么宏的行为类似于宏?”我认为你真的想问 Sam Estep 提到的问题之一,所有这些问题都是关于合理的问题。

标签: clojure


【解决方案1】:

让我们从许多人非常了解的一件事开始,他们在解释宏时忘记了明确地考虑它,这导致其他人在学习考虑宏时感到困惑:

------------> 宏是函数

它们经常用于获取看起来像代码的东西的列表,并且通常期望返回实际上可以作为代码运行的列表。

宏和函数之间的区别不是它做什么(基本上),而是它什么时候做。 宏在代码“加载”时运行,它们返回的值在程序运行时运行。

当您将其编写为宏时,它会执行两个步骤:

  • 运行函数生成列表
  • 将返回的列表作为代码运行以生成值

当你把它写成一个函数时,它会执行一个步骤:

  • 运行函数生成列表

然后它停止。

返回值不同,因为宏版本采取了将返回值作为代码运行的额外步骤。

代码就是数据……数据就是代码……耶,口齿不清!

【讨论】:

  • 我一直在应用类似的思维过程来理解宏。在 REPL 过程中,宏位于 Read 和 Eval 之间。这就是为什么要评估宏的返回值的原因,因为“读取”已经发生。另一方面,函数被评估,它的返回值是为了提供给读者。我可能错了。我还在想。
  • 仔细想想,函数的返回值是要打印出来的,或者执行过程会循环回来,返回值输入到“读取”步骤。
  • @ardsrk 是的,你明白了。它循环回到读取阶段,如果它在第二遍仍然是一个宏,那么它再次循环回来进行第三遍。一直走下去,直到没有宏。然后最终完全形成的代码实际上会进入完成的程序。
  • 你提出了一个有趣的观点。请详细说明您对第二遍及更多的评论。我在想,既然函数可以返回一个函数,它也可以返回一个宏......
  • 是的,那是正确的:如果它返回的表达式(通常是列表)是一个函数调用(when ...) 并且该函数被标记为一个宏,那么它会再次循环。如果函数不是宏,则它停止循环并将其作为最终代码/表达式返回。宏是带有一些额外元数据的函数,上面写着“我是宏”,这是使它们成为宏的唯一区别。运行(meta #'clojure.core/when) 并查看:macro
猜你喜欢
  • 1970-01-01
  • 2021-05-24
  • 1970-01-01
  • 1970-01-01
  • 2017-11-25
  • 1970-01-01
  • 2019-01-08
  • 1970-01-01
  • 2018-03-08
相关资源
最近更新 更多