Clojure的宏[1]

2017/07/28 Clojure学习

1. 宏是什么?

是什么,搞过c++的一定不陌生,宏就是用来告诉编译器如何编译的一些指令,如何通俗的理解宏呢? 以来来源于: 维基百科-宏

计算机科学里的宏是一种抽象(Abstraction),它根据一系列预定义的规则替换一定的文本模式。解释器或编译器在遇到宏时会自动进行这一模式替换。对于编译语言,宏展开在编译时发生,进行宏展开的工具常被称为宏展开器。宏这一术语也常常被用于许多类似的环境中,它们是源自宏展开的概念,这包括键盘宏和宏语言。绝大多数情况下,“宏”这个词的使用暗示着将小命令或动作转化为一系列指令。 宏的用途在于自动化频繁使用的序列或者是获得一种更强大的抽象能力。

2. 编译期和运行期间

不出意外的,作为一个表现能力强悍的lisp在jvm上的方言clojure,当然不会缺少了这个神奇的了.宏最为clojure上一个强有力的抽象工具,是让我这样的新手又爱又怕,喜欢他的强大,但是又怕难以驾驭. 让我们可控制clojure的编译器.我们通常把java称为没有枪,没有刀的C++,把ruby和python称为"兵工厂",而clojure的宏可以使你构建任何武器,并且让你的武器使用起来和语言的内置武器么有什么区别. 要理解宏,就要先理解"编译期""运行期"的区别. Clojure在载入源码的时候,也就是你写的Code再被Clojure Reader读入的时候,文本形式的Clojure代码会转变成List[也就是Clojure里面的数据结构],read会对list进行求值,编译发生在read和求值之间,而正是这个编译的过程,使得宏的展开成为了可能.换句话说,是被编译器调用的. 为何Clojure会有这种神奇的现象,是因为一个成为同像性的特性,嗯?同像性是个什么梗?

一门语言的代码可以用语言自身的数据结构来描述,这一特性被称为同像性.

3. Clojure里面的宏

在Clojure的世界里,使用defmacro就可以定义一个宏.so,魔法如此简单. 仔细想一想,有哪些常用的宏呢?

->
->>

是不是很熟悉? ->->>这两个串行宏和,,下一篇文章咱们就自己用实现一个这个玩意.

3.1 手法 ~@ ` ~

要写,要写好,就要先了解这几个东西:

语法引述[synatx quote] 返引述[unqute] 编接反引述[splicing-quote]

这些语法并不是专门为了Clojure的宏设计的,你可以在其他代码中使用它们.

3.1.1 语法引述[synatx quote] —>`

你可以理解为阻止求值,当我们要保留一段代码的是写模样的时候,使用这个符号,那么在Clojure Reader的时候不会对你写的表达式进行求值,从而保持住书写时的样子. 例如让我们书写:

(1 2 3 4) ;ok没有问题.
(+ 1 2 3);也许你想要的是一个list,里面保存有+ 1 2 3,但是这段代码却被求值了,变成了你不想要的 6
(1 + 3 2);这段直接报错了.

没错,那么我们如何让(+ 1 2 3)或者是(1 + 3 2)保持住这个list的状体而不被求值呢?很简单,在他们的前面增加 ` 就ok了.

`(+ 1 2 3);ok,没问题
`(1 + 3 2);ok,没问题

对,没错,就是这么简单.

3.1.2 返引述[unqute] ———-> ~

那么什么是反引述呢? 其实就是个 ~,对,就是这个符号. 那么这个~有和作用呢?他的作用就是在阻止求值的表达式里进行正常的求值.

`(+ 1 2 3 4 (+ 10 10))

这个表达式会被阻止求值,保持原样.但是咱们要的是结果是(+ 1 2 3 4 20) 咱们要怎么对需要进行求值的地方正确的求值呢? 这时候就要用到~了,如下:

`(+ 1 2 3 4 ~(+ 10 10))

这样的代码跑过后就成了(+ 1 2 3 4 20),果不其然就是咱们想要的了.

3.1.3 编接反引述[splicing-quote]–> ~@

这个就好玩, ~@神奇的东西,这个东西姑且可以理解为讲一个变量多代表的内容进行展开并且阻止求值,由于Clojure本身就是List,因此这个变的十分有趣.

(defmacro foreach [x y& body]

3.2 &evn和&from

pass

3.3 卫生宏(宏污染)和sysgems

pass

3.4 重复求值问题

pass

Clojure编译模型

Clojure编译模型

Search

    Table of Contents