7

Lisp/Clojure 代码在语法上具有一致性,这是一个优点,因为不需要理解各种不同的结构。但有时通过使用不同的语法来查看一段代码更容易理解,例如这是一个 switch case,或者这是模式匹配结构等,而无需实际阅读文本。

几个月前我开始使用 Clojure,我意识到如果不阅读表单的名称,然后在谷歌上搜索它是宏还是函数以及它是如何工作的,我将无法理解代码。

所以事实证明,一段 Clojure 代码,无论语法的统一性如何,都是不统一的。

它可能看起来像一个函数,但如果它是一个宏,那么它可能不会评估它的所有参数。

是否有所有宏都使用的命名约定或缩进样式,以便某人更容易通过名称掌握发生了什么?

4

3 回答 3

4

在我看来,最有用的直觉来自于理解给定运算符 / Var 的目的。设计良好的宏根本不能写成函数,并且仍然以相同的语法提供相同的功能,因为如果可以的话,它们实际上会被写成函数(参见上面的“精心设计”部分!)。1因此,如果您正在处理一个不可能是常规函数的构造,那么您就知道它不是;否则很可能是。

此外,了解库导出的 Var 的常用方法会告诉您预先处理的是宏还是函数。对于doc((doc foo)表示foo如果确实是这种情况,这是一个靠近其输出顶部的宏),source(因为它为您提供了整个代码) 和M-.(使用 nrepl.el 或 swank-clojure 跳转到 Emacs 中的定义;M-,跳转背部)。文档可能会提及什么是宏,什么不是(除非文档字符串不一定如此,因为访问文档字符串的所有常用方法都已经告诉您是否正在处理宏,如上所述)。

如果您浏览一段代码的目的是粗略理解它可能在假设各种运算符执行其名称所暗示的功能的情况下可能会做什么,那么(1)这些名称具有足够的暗示性并且您会得到了解代码的意图,因此您甚至不需要关心哪些运算符恰好是宏,或者 (2) 名称的暗示性不够,因此您需要深入研究文档或源代码无论如何,一些运算符,然后您将学习的第一件事是它们中的哪些被注册为宏。

最后,宏没有单一的命名风格,尽管有一些特定于特定用例的约定。例如with-foo-style 结构往往是便利宏,其目的是简化对 type 资源的处理foodofoo-风格的结构往往是宏,它需要执行一组表达式(多少次以及设置额外的上下文取决于宏;这个家族中最基本的成员,do实际上是一种特殊形式而不是宏); deffoo-style 构造引入了新的 Var 或类似类型的实体。

值得指出的是,类似的模式有时会被打破。例如,大多数线程构造 ( ->& Co.) 是宏,但xml->fromclojure.data.zip.xml是一个函数。当考虑到所提供的功能时,这是完全有道理的,这让我们回到了运营商作为最有用的直觉来源的目的这一点。


1此规则可能有一些例外情况。人们会期望这些被记录在案。当然,有些项目根本没有记录(或几乎没有记录);在这里,问题完全消失了,因为无论如何都必须找到源头才能理解事物。

于 2013-07-24T07:02:12.837 回答
1

通常有两个属性可以将宏(或有时是特殊形式)与函数区分开来:

  1. 当表单进行某种绑定时(即声明新的标识符供以后使用)
  2. 当一些参数被懒惰地评估时

第一种情况的示例是letletfn和。奇怪的是,它被定义为一个函数,但我很确定它与 Clojure 的引导过程有关(在定义之前定义)。bindingwith-local-varsdefndefndefmacro

第二个例子是and,orlazy-seq。在所有这些构造中,通过将参数放在条件分支(如if)或将它们移动到函数体中来懒惰地评估参数。

这两个属性实际上只是宏操作 Clojure 语法的表现。我不认为线程宏 (->->>) 非常适合这些类别,但是零安全版本​​ (-?>-?>>) 属于具有惰性参数

于 2013-07-24T07:22:02.357 回答
0

据我所知,没有强制的命名约定。

根据经验,尽可能首选函数,但是当宏遵循def<something>设置某事物或with-<resource>使用开放资源做某事的模式时,有时会发现宏。

因此,您可能会发现 clojure 的doc宏很有帮助。它会告诉你表单是否是宏/函数/特殊表单,并给出它的参数列表和文档字符串(如果存在)。例如

(use 'clojure.repl)
(doc and)

将以下内容打印到 repl。

clojure.core/和

([] [x] [x & 下一个])

从左到右,一次评估一个 expr。如果表单返回逻辑假(nil 或假),并返回该值并且不计算任何其他表达式,否则返回最后一个 expr 的值。(and) 返回真。

一些编辑器(例如 emacs)会以弹出窗口或组合键的形式提供此文档,这使得访问(和阅读)更快。

于 2013-07-24T06:59:40.543 回答