『阿男的编程本质论』*10 Eval,Macro,Preprocessor,Homoiconicity(三)*
2017-01-16 00:00
330 查看
『阿男的编程本质论』*10 Eval,Macro,Preprocessor,Homoiconicity(三)*
那么Clojure这种macro和C语言里面
因此C语言的preprocessor处理它的macro的时候,就是简单的文本替换。开源的preprocessor,
我们可以想一下编译原理相关知识,在Parser处理代码之前,有Tokenizer(也叫Lexer)会把代码转化成token,这种转化,就是把文本转化成结构的基本单元token。这样的话,Parser才能更好地分析语法规则,把tokens联系在一起,变成树形结构AST。因此"结构"在这里面起了很大的作用。
而Clojure里面的macro则是有效的语法结构,本身它的代码就是list数据,list数据本身也可以表示树形结构(通过nested的括号),因此可以说Clojure的Lexer和Parser要做的事情被大大简化了,当然也导致了Clojure了Lisp这种语言的语法显得比较"原始"。但是在上篇文章里,我们也看到了,Clojure的macro功能非常灵活,我们可以直接把传入macro的list数据(也即是代码)进行各种改写,而且这种改写不是简单地文本替换,而是对list数据的操作。
此外,Clojure的macro展开是在compile过程中完成,因此如果我们的macro写的有问题,在compile过程中就会给出报错和相关错误位置。
我们刚才也说了,C语言也有macro的概念,比如
这种macro展开有什么问题?阿男觉得最大的问题就是,如果你的macro里面被替换过来的代码有bug,compiler在compile过程时拋给你的错误往往特别难以理解,因为我们的macro实际上已经被展开成了完全不同的内容。如果这个内容里面有错误,compiler会报相关的错误,但是做为程序员,这个错误从哪里来的成了一个问题。
比如
那么Clojure这种macro和C语言里面
#include这种macro有什么区别呢?C语言里面的macro实际上就是一种文本替换,比如
#include "foo.h"在编译的时候就是会把
foo.h里面的内容替换到
#include "foo.h"这里。
因此C语言的preprocessor处理它的macro的时候,就是简单的文本替换。开源的preprocessor,
m4就是这样的工具。当然
m4这种macro expander也支持一些条件语句来进行一定限度上的根据字串里面的一些特征进行有条件替换,但这毕竟还是把输入作为字符串,而不是结构,来进行处理,这种替换方式必定有局限性。
我们可以想一下编译原理相关知识,在Parser处理代码之前,有Tokenizer(也叫Lexer)会把代码转化成token,这种转化,就是把文本转化成结构的基本单元token。这样的话,Parser才能更好地分析语法规则,把tokens联系在一起,变成树形结构AST。因此"结构"在这里面起了很大的作用。
而Clojure里面的macro则是有效的语法结构,本身它的代码就是list数据,list数据本身也可以表示树形结构(通过nested的括号),因此可以说Clojure的Lexer和Parser要做的事情被大大简化了,当然也导致了Clojure了Lisp这种语言的语法显得比较"原始"。但是在上篇文章里,我们也看到了,Clojure的macro功能非常灵活,我们可以直接把传入macro的list数据(也即是代码)进行各种改写,而且这种改写不是简单地文本替换,而是对list数据的操作。
此外,Clojure的macro展开是在compile过程中完成,因此如果我们的macro写的有问题,在compile过程中就会给出报错和相关错误位置。
我们刚才也说了,C语言也有macro的概念,比如
#include <stdio.h>,这种macro也是在compile时展开,但是C语言的这种macro就是文本替换,比如这个
#include <stdio.h>在compile过程中,就是被替换成
stdio.h文件里面的内容。
这种macro展开有什么问题?阿男觉得最大的问题就是,如果你的macro里面被替换过来的代码有bug,compiler在compile过程时拋给你的错误往往特别难以理解,因为我们的macro实际上已经被展开成了完全不同的内容。如果这个内容里面有错误,compiler会报相关的错误,但是做为程序员,这个错误从哪里来的成了一个问题。
比如
stdio.h假设有代码bug,那么你的代码如果使用
#include引用了
stdio.h,那么compiler会在compile的时候把
stdio.h的具体内容替换到
#include <stdio.h>的位置。这样的话,当
stdio.h里面有bug的时候,compiler会报具体的bug。但你看这个bug就会很头疼,因为那个具体的bug根本就不在你的代码里面而是在
stdio.h里面,这就造成理解上的困难。所以C语言这种基于文本替换的macro展开,和Clojure这种代码即数据的macro展开是完全不同的。
相关文章推荐
- 『阿男的编程本质论』*09 Eval,Macro,Preprocessor,Homoiconicity(二)*
- 『阿男的编程本质论』*11 Eval,Macro,Preprocessor,Homoiconicity(四)*
- 『阿男的编程本质论』*08 Eval,Macro,Preprocessor,Homoiconicity(一)*
- 术语:Homoiconicity(同像)
- Homoiconicity
- 『阿男的编程本质论』*08 正则表达式是万能的吗?*
- 也谈编程本质
- 汇编语言:实验10 根据材料编程—2.解决除法溢出的问题
- Racket编程指南——10 异常与控制
- 阻塞/非阻塞读写总结、tcp网络编程的本质、muduo::Buffer设计简介
- 黑马程序员之WinForm编程基础学习笔记:日月选择器,假设2月份总是28天。1,3,4,7,8,10,12月份是31天,其他是30天。
- 2017 年最受欢迎的 10 个编程挑战网站
- Android 的网络编程(10)-网络权限配置
- obj-c编程10:Foundation库中类的使用(2)[字符串,数组]
- obj-c编程10:Foundation库中类的使用(4)[文件管理,查询当前进程信息]
- 02_编程实现1!+2!+……+10!的和
- Tensorflow实现CIFAR-10分类问题-详解四cifar10_eval.py
- python2.7学习笔记(10) ——面向对象高级编程
- CC++初学者编程教程(10) 搭建Android java C/C++ NDK QTforAndroid 开发环境
- 10:判决素数个数(1.13编程基础之综合应用)