我对Clojure相对较新,并且不能完全理解 reader宏和常规宏之间的区别,以及为什么差异很大。
在什么情况下你会使用一个而不是另一个?为什么?
答案 0 :(得分:6)
Reader宏将语言的语法(例如,@foo
转换为(deref foo)
)以普通宏不能的方式更改(普通的宏无法摆脱括号,所以你必须做(@ foo)
之类的事情。它被称为 reader 宏,因为它是在repl的read
传递中实现的(请查看source)。
作为一个clojure开发人员,你只会创建常规宏,但你会使用大量的阅读器宏,而不必明确考虑它们。
读者宏的完整列表位于:https://clojure.org/reference/reader,其中包括@
'
和#{}
等常见内容。
Clojure(与其他一些lisps不同)不支持用户定义的读取器宏,但是通过tagged literals(例如#inst
或#uuid
)<读取器内置了一些可扩展性/ p>
答案 1 :(得分:4)
<强> TL;博士* 强>
宏[普通宏]在评估期间(REPL的E)展开,与符号相关联,对lisp对象进行操作,并出现在表单的第一个或“函数”部分。 Clojure和所有lisps都允许定义新的宏。
在评估之前,读取期间运行的读取器宏是单个字符,在从读取器发出的所有lisp对象之前对字符串进行操作,并且不限于在第一个或“函数”中,表格的一部分。与其他一些lisps不同,Clojure不允许定义新的阅读器宏,而不是编辑Clojure编译器本身。
更多字词:
普通的非读者宏,或只是“宏”,对lisp对象进行操作。考虑:
(and 1 b :x)
将使用两个值调用and
宏,一个值为1
,另一个值为包含符号b
(不是b的值)和关键字的列表:x
。 and
宏正在处理的所有内容都是lisp(Clojure)值。
宏扩展仅在宏位于列表的开头时发生。 (and 1 2)
扩展了and
宏。 (list and)
返回错误“无法获取宏的值”
读者负责将字符串转换为In Clojure,读取器宏是一个单一字符,可以改变读者(负责将文本流转换为lisp对象的部分)的操作方式。 Clojure的lisp阅读器的发送在LispReader.java。正如Alejandro C.所述,Clojure不支持添加阅读器宏。
Reader宏是一个字符。 (我不知道所有lisps是否都是如此,但Clojure目前的实现仅支持单字符读取器宏。)
Reader宏可以存在于表单中的任何位置。考虑(conj [] 'a)
如果'
宏是正常的,则需要将tick作为lisp对象,因此代码将成为符号conj
的列表,一个空向量,符号{{ 1}},最后是符号'
。但现在,评估规则要求a
自己进行评估。相反,读者在看到'
包装后跟'
的完整s-exp时,返回给评估者的值是quote
列表,空向量和a conj
后跟quote
的列表。现在a
是列表的头部,可以更改其引用的评估规则。
答案 2 :(得分:1)
简单地说,读者宏是一个低级功能。这就是为什么他们这么少(只有@
,退出和更多)。拥有许多读者规则会使任何语言变得混乱。
常规宏是在Clojure中广泛使用的工具。作为开发人员,如果您不是Clojure的核心开发人员,欢迎您编写自己的常规宏,而不是读者。
您可以随时使用自己的标记文字作为读者规则的替代,例如#inst "2017"
会为您提供Date
个实例,等等。