published on
tags: reading scheme pl

书籍推荐 《Programming Languages: Application and Interpretation》

正好赶上劳动节要放假了,在网上转悠的时候发现这本书。用来讲述编程语言特性的一门课程。这本书可以在线阅读,用plai作为关键词google一下就可以找到。

按照一般的作风,这里应该放一张封面的靓照,我就省去了。

今天简单的看了一下,非常喜欢,很快看到了第15章。书中的代码都是用的scheme实现的,不过为了教学目的,对scheme做了扩展,形成了专门为这个教学使用的语言。如果没有scheme经验的同学可以先看看《SICP》打打底。

书中的主要内容就是介绍语言的各种特性。方法就是通过编写具有这各种特性的语言的解释器。了解多种语言的特性可以帮助你理解在各种语言中,那些设计为什么要做成那样,哪些地方是好的设计,哪些地方实际上应该可以更合理。

说明: 后面关于书的内容的介绍是基于07版的,其网站上有2007版和 2012版两个版本的下载,而我是拿着07版在看,预计看完之后快速过一下新版的修改的内容完事了。

最开始,先是做了一些基本的介绍,说我们研究的不是具体的语法,而是语义。也就是区分不同语言的关键不在于看起来写成什么样,而是其具体有什么作用。所以用lisp有一个巨大的方便之处就在于不用在语法这件事情上纠结了,可以方便的得到ast,然后在上面做工作。

第二部分先实现了一个具有基本功能的语言,包括基本的计算和函数调用。同时会介绍static scopedynamic scope的区别。

第三部分讲惰性求值,举了两个例子,其一是Haskell,这个是很标准的惰性求值的语言。不多说,另一个是unix的管道的设计。管道的作用是将一个程序的输出作为另一个程序的输入。而输出会造成阻塞,只有另一个程序将这写输入了之后,前一个程序才会继续运算,所以这个设计就和惰性求值有着一样的特性:可以处理无限。例子比如命令 yes | head -n 5 就会输出5个y,而仅仅是yes的话,就会产生无穷的y,可以你要多少给多少。比如用在yes | rm * 这样的命令中就会很方便。

这里面提到unix的一个设计的哲学就是为10个元素提供10种工具,不如为1种元素提供100种工具,然后将这些工具组合起来就得到非常强大的力量。在unix中这个东西就是stream,但是最后这个东西有个缺陷,就是不便于表达结构化的数据,一切都为了内容是可读的。

这里其实隐含这再说lisp才是最牛逼的,这里什么都是用s表达式表示的,有大量操作s表达式的操作,所有的运算的输入和输出都是s表达式。多么美好啊。当然如果看前缀的算术表达式能习惯的话,是挺不错的。

这里扯多了,第四部分讲递归是怎么实现的。为了构造循环的Env,使用了初次使用了box功能。也就是说引入了非pure functional的部分,对已有的值进行了修改,否则很难想象怎么构造一个环:1.A引用B,2.而B引用A,1要求在你构造A的时候B已经构造好了,而2相反,所以只能先构造一个再改了。

第五部分简单的讲了一下我们不一定要用原生的类型来表示新语言中的值,比如你用C写一个解释器,解释的语言的整数在C中也可能是个string或者和struct什么的。在scheme里面我们甚至可以完全就靠闭包来当作数据结构使用,模拟各种值的行为(当然性能就很微妙了)

这只是一个简单的过场

第六部分开始为我们要解释的语言加入了副作用。显示加入了box和unbox这样的功能,类似C里面的指针,虽然没有赋值,指针不能变,但是我们可以改变指针指向的东西了。

之后要允许变量直接赋值了,修改变量的值相当于取出变量对应的地址,然后改对应地址的值。

出现变量赋值后,就又提出了一个问题,函数调用的时候就产生了两种方式传值和传引用。

整体来看这里已经涉及了比较丰富的概念了内容了。

后面的内容我还没有看,只是简单的过一下目录,下面概括一下,有机会以后再展开讨论。

第七部分讲延续(Continuations),通过web程序的特点引入的。然后提到了CPS转化,再引入延续,最后将怎么实现。不了解的同学或者听说过协程(Coroutines),其和延续关系非常大,具体不多转述。CPS的话可以参看一些node.js的资料应该会有个大致的印象。

第八部分讨论内存管理的思路,比较像C那样显式malloc free和函数式语言那样自动分配的区别。

第九部分专门讨论语义,具体看后再说。

第十部分类型系统,最后会涉及自动类型推导,目测会比较有意思。

第十一部分搜索,实现一个prolog那样工作的语言

第十二部分DSL和metaprogramming,元编程,让人疯狂的宏