Robpike/Lisp:围棋中的玩具Lisp1.5解释器

2020-06-17 15:46:51

这是一种语言的实现,在1962年麻省理工学院的McCarthy、Abrahams、Edwards、Hart和Levin所著的LISP 1.5程序员手册的前几页中以极高的简洁性定义了该语言。

这是一个教学实验,目的是看看该书第13页上定义的解释器(实际上是EVALQOUTE/APPLICE)工作得有多好。答案是:当然是完美的。

把这个节目放在一起是一件令人愉快的事。它的目的是娱乐和教育,而不是以任何方式创建一个现代的甚至现实的Lisp实现。我们的目标是使用干净、直接的GO代码将这个令人惊叹的第13页变成一个可以工作的解释器。

因此,即使对于Lisp1.5这本书,该程序也有几个严重的缺陷:

没有节目。通过调用Apply,解释器只能计算单个表达式,即可能的递归函数调用。但这是里斯普,这仍然很多。

无I/O。仅限交互式,尽管它可以通过读取命令行上指定的文件启动。

它很慢,当然,它的语言与Common Lisp或Scheme相去甚远。

虽然有一天我可能会添加prog并设置[q],但这就是我要划清界限的地方。我计划将其用作教学工具,而不是实用的编程环境。

不过,它确实做了一件与本书不同的重要事情:词汇作用域。没有关联列表;相反,函数只能访问其自身框架中的局部变量,以及T等全局变量。

T和F是大写的,但所有其他单词(car、nil等)都是小写的。

数字是由GO的Big.Int实现的,所以没有浮点,但是数字可以很大。

标识符可以是Unicode。只是为了好玩,λ是lambda的同义词。(实际上正好相反,不是吗?)。

我从来不喜欢键入差或商,所以算术使用更短的add sub mul div rem,比较操作符来自Fortran(何乐而不为呢?):eq ne lt le gt ge ne,以及and和or。

(defn((add2(λ(N)(Add2 N)(add4(λ(N)(add2(Add2 N)。

这是一份打字稿。lib.lisp中有一个库;将其作为参数传递会导致LISP在读取标准输入之前加载它。

%lisp lib.lisp(fac gcd ack等于Not Negate mapcar length opn成员并集交集)>;;Funcs>;(Add 1 3)4>;;定义添加2的lambda。(defn((add2(lambda(N)(Add 2 N)(Add 2)(Add2)>;(Add2 3)5>;或添加1两次。(defn。(Add2 3)5;lisp.lib中有一个启动库。让我们来看看facc。它是递归的:>;fac(lambda(N)(cond((Eq N 0)1)(T(mul n(fac(Subn 1)>;;分解:>;(Car Fac)lambda>;(Cadr Fac)(N)>;(Caddr Fac)(cond((Eq N 0)1)(T(mul n(fac(Subn 1)。(FAC 10)3628800>;;我们有大整数。>;(fac 100)93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000>;;等于Lisp>;等于(λ(Xy)(cond((等式xy)T)((原子x)F)((原子y)F)((等于(Car X)(Car Y)(等于(Cdr X)(Cdr Y)(T F)>;(等于';(1 2(3))&。(1 2(3))T>;(等于';(1 2(3))';(1 2(4))F>;;Mapcar,Lisp订书符:对每个列表元素应用函数。>;mapcar(lambda(Fn List)(cond((Null List)nil)(T(cons(fn(Car List))(mapcar FN(Cdr List)>;(1 2 3 4 5 6 6 7 8 9 10))(1 2 6 24 120720 5040 40320 362880 3628800)>;;直接使用lambda。>;(mapcar';(lambda(N)(add 1(Add 1 N)';(234))(4 56)>;让我们构建一个函数。>;A helper:List比使用cons构建长列表更容易。(变量)>;(列表';a';b';(C))(a b(C))>;比>;(cons&39;a(cons';a(cons';b(cons(#39;c nil)nil)(a b(C))>;记得我们是如何构建上面的add2的:>;(defn((add2(lambda(N))。现在构建一个将任意N加到其参数中的函数。>;(Defn;(Defn;((addN(lambda(N)(list';lambda';(A)(list';add N';a)(AddN)>;(AddN 5)(lambda(A)(Add 5a))>;((AddN 5)3)无法求值((AddN 5)3)>;;A LisS。(Apply(AddN 5)3)8&>;(mapcar(AddN 5)';(1234))(6 789)>;;为什么不也对OP进行编程?>;(defn((opn(lambda(Op N)(list';lambda';(A)(list op N';a)(list op N';a)(Opn)>;(mapcar(opn'。(1234))(4321)>;;最后一个有趣的部分:Ackermann函数。>;;第一个参数是一种级别:常数,n,2n,2^n 2^2^n等>;ack(lambda(M N)(cond((Eq M0)(Add N 1))((Eqn0)(ack(Subm1)1)(T(ack(Subm1)(ack m(。应用程序调用51535次!125^D%