"常规"有什么区别?和#34;读者"宏?

时间:2017-05-22 13:16:06

标签: clojure macros

我对Clojure相对较新,并且不能完全理解 reader宏常规宏之间的区别,以及为什么差异很大。

在什么情况下你会使用一个而不是另一个?为什么?

3 个答案:

答案 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的值)和关键字的列表:xand宏正在处理的所有内容都是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个实例,等等。