基于环境模型的解释器
光剑系列的第五作!前四篇: 第一篇:Let’s build our mathematics by using lambda calculus && church encoding! 第二篇:惰性求值、无穷流与发生的魔法 第三篇:协程、生成器与 call/cc 的控制流 第四篇:动态作用域、词法作用域与表达式求值的环境模型 前言 又见面了!上一篇文章中我将动态作用域的实现留作了习题,一定非常恶心吧!毕竟我尝试了两天枚举了各种不用宏和用宏的解决方案都没有任何成果,只能看着看不懂的编译错误或者不期望的展开结果发呆。 如果有哪位读者做出了那个习题,请务必通过本文评论区联系我。 不过,其实只要自己实现一个解释器,就能够轻松而优雅地完成这个习题。 恰好,上一篇文章中介绍了环境模型,这将是我们解释器的原理。 我们将选择 scheme 实现解释器。因为 scheme 的解释器特别好写而作者太菜了只会这个。 实现 在实现一个具有比较多特性的 scheme 子集之前,我们将先实现一个更简单的 lambda 演算解释器。 看过第一作的读者们想必还记得 lambda 演算吧?它只含有函数一种对象,函数抽象和函数应用两种操作,已经是图灵完备的。 那么我们来实现它,使用环境模型和闭包。 预备工作 · 函数 lambda 只有函数一种核心对象。实现函数自然成为了我们的重要任务。 在环境模型下,想要实现词法作用域肯定要用闭包。所以我们的函数也将被表示为一个闭包。 它含有四个字段:第一个是符号 closure,用于标识身份。后面三个字段分别是形式参数、函数体和保存的环境。这些是闭包的核心要素。 我们可以先实现单参数的函数。因为具有一等公民函数的特性,我们可以通过柯里化实现多参数函数。 对于闭包的存储,随便用什么都行。我用的是一个 vector(定长数组)。 1 2 (define (make-closure params body env) (vector 'closure params body env)) 有了函数的数据结构标识,我们还需要有对于闭包的操作: 1 2 3 4 5 6 (define (closure? obj) (and (vector? obj) (eq? (vector-ref obj 0) 'closure))) (define (closure-param closure) (vector-ref closure 1)) (define (closure-body closure) (vector-ref closure 2)) (define (closure-env closure) (vector-ref closure 3)) 然后,为了支持对于函数的应用和抽象,我们需要一些关于环境的操作。 ...