码迷,mamicode.com
首页 > 其他好文 > 详细

简单易懂的程序语言入门小册子(7):基于文本替换的解释器,加入continuation,重构解释器

时间:2014-05-05 22:13:58      阅读:337      评论:0      收藏:0      [点我收藏+]

标签:style   blog   class   code   tar   ext   

或许在加入continuation之前要先讲讲费这么大劲做这个有什么意义。 毕竟用不用continuation的计算结果都是一样的。 不过,这是一个兴趣使然的系列,学习这些知识应该完全出于好奇与好玩的想法。 所以我才不会告诉你们通过控制continuation可以实现call-with-current-continuation和异常处理等功能呢。

我先简要描述一下加入continuation后解释器是怎么工作的。 加入continuation后的解释器是以迭代的方式工作的。 迭代的状态量有两个,第一个是一个待求值的表达式或者求到的值,第二个是Continuation。 假设解释器的输入是Mbubuko.com,布布扣 ,那么一开始的状态表示为?M,mt?bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣 。 第一个状态量是个表达式Mbubuko.com,布布扣 ,这时解释器开始对Mbubuko.com,布布扣 求值。 这个过程用记号bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣 表示。 这个过程可能会将一些“下一步要做的事”保存到continuation。 求值到最后,状态会变为?V,κ?bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣 (如果没有无限循环)。 注意到下标变成c,Vbubuko.com,布布扣 是一个值,所以不能再求值了,下一步要做的是从continuation κbubuko.com,布布扣 中取出“下一步要做的事”执行。 这个过程也叫做“将continuation κbubuko.com,布布扣 应用到值Vbubuko.com,布布扣 ”,用记号bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣 表示。 一个解释器的执行过程就是bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣 bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣 交替运行,就好像太极里阴阳交替一样。 解释器执行到最后状态会变成?V,mt?bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣 ,已求得值Vbubuko.com,布布扣 ,又没有“下一步要做的事”,也就是运行结束了,输出Vbubuko.com,布布扣 。 说了这么多,本质上整个过程还是一句话:递归转迭代。顺便一提,加入continuation后的解释器叫做CK machine。

先列出目前为止的所有求值过程(call-by-value):

  eval(X)bubuko.com,布布扣  eval(b)bubuko.com,布布扣  eval(λX.M)bubuko.com,布布扣  eval((+MN))bubuko.com,布布扣  eval((?MN))bubuko.com,布布扣  eval((iszeroM))bubuko.com,布布扣                 bubuko.com,布布扣  eval((iszeroM))bubuko.com,布布扣                 bubuko.com,布布扣  eval((MN))bubuko.com,布布扣                 bubuko.com,布布扣  eval((fixXbubuko.com,布布扣1bubuko.com,布布扣Xbubuko.com,布布扣2bubuko.com,布布扣M))bubuko.com,布布扣bubuko.com,布布扣=bubuko.com,布布扣=bubuko.com,布布扣=bubuko.com,布布扣=bubuko.com,布布扣=bubuko.com,布布扣=bubuko.com,布布扣bubuko.com,布布扣=bubuko.com,布布扣bubuko.com,布布扣=bubuko.com,布布扣bubuko.com,布布扣=bubuko.com,布布扣bubuko.com,布布扣Xbubuko.com,布布扣bbubuko.com,布布扣λX.Mbubuko.com,布布扣eval(M)+eval(N)bubuko.com,布布扣eval(M)?eval(N)bubuko.com,布布扣truebubuko.com,布布扣其中eval(M)=0bubuko.com,布布扣false,bubuko.com,布布扣其中eval(M)0bubuko.com,布布扣eval(L[Xeval(N)])bubuko.com,布布扣其中eval(M)=λX.Lbubuko.com,布布扣λXbubuko.com,布布扣2bubuko.com,布布扣.M[Xbubuko.com,布布扣1bubuko.com,布布扣(fixXbubuko.com,布布扣1bubuko.com,布布扣Xbubuko.com,布布扣2bubuko.com,布布扣M)]bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣
下面分别介绍各个情况下如何加入continuation。

值与fix表达式

值是最简单的情况,直接应用continuation。

  ?X,κ?bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣  ?b,κ?bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣  ?λX.M,κ?bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣?X,κ?bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣?b,κ?bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣?λX.M,κ?bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣

fix表达式和值的情况类似:

  ?(fixXbubuko.com,布布扣1bubuko.com,布布扣Xbubuko.com,布布扣2bubuko.com,布布扣M),κ?bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣    ?λXbubuko.com,布布扣2bubuko.com,布布扣.M[Xbubuko.com,布布扣1bubuko.com,布布扣(fixXbubuko.com,布布扣1bubuko.com,布布扣Xbubuko.com,布布扣2bubuko.com,布布扣M)],κ?bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣

基本运算

(obubuko.com,布布扣nbubuko.com,布布扣Mbubuko.com,布布扣1bubuko.com,布布扣Mbubuko.com,布布扣2bubuko.com,布布扣...Mbubuko.com,布布扣nbubuko.com,布布扣)bubuko.com,布布扣 表示基本运算,其中obubuko.com,布布扣nbubuko.com,布布扣bubuko.com,布布扣 是运算符,Mbubuko.com,布布扣1bubuko.com,布布扣,...,Mbubuko.com,布布扣nbubuko.com,布布扣bubuko.com,布布扣 是参数,nbubuko.com,布布扣 是代表参数个数。 在我们的语言里目前有两个两参数的基本运算obubuko.com,布布扣2bubuko.com,布布扣={+,?}bubuko.com,布布扣 和一个单参数的基本运算obubuko.com,布布扣1bubuko.com,布布扣={iszero}bubuko.com,布布扣

计算基本运算前要先对所有参数求值。这里规定从左到右求值。 当解释器在求第ibubuko.com,布布扣 个参数Mbubuko.com,布布扣ibubuko.com,布布扣bubuko.com,布布扣 的值时,需要保存到continuation的数据有: 运算符obubuko.com,布布扣nbubuko.com,布布扣bubuko.com,布布扣 、 已求到的值Vbubuko.com,布布扣1bubuko.com,布布扣,...,Vbubuko.com,布布扣i?1bubuko.com,布布扣bubuko.com,布布扣 (其中Vbubuko.com,布布扣1bubuko.com,布布扣=eval(M),...,Vbubuko.com,布布扣i?1bubuko.com,布布扣=eval(Mbubuko.com,布布扣i?1bubuko.com,布布扣)bubuko.com,布布扣 ) 以及还没求值的参数Mbubuko.com,布布扣i+1bubuko.com,布布扣,...,Mbubuko.com,布布扣nbubuko.com,布布扣bubuko.com,布布扣 。 因此,包含基本运算的continuation定义为:

  κbubuko.com,布布扣         bubuko.com,布布扣bubuko.com,布布扣=bubuko.com,布布扣|bubuko.com,布布扣bubuko.com,布布扣mtbubuko.com,布布扣?opd,κ,obubuko.com,布布扣nbubuko.com,布布扣,(Vbubuko.com,布布扣1bubuko.com,布布扣...Vbubuko.com,布布扣i?1bubuko.com,布布扣),(Mbubuko.com,布布扣i+1bubuko.com,布布扣...Mbubuko.com,布布扣nbubuko.com,布布扣)?bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣

求值过程为:

  ?(obubuko.com,布布扣nbubuko.com,布布扣Mbubuko.com,布布扣1bubuko.com,布布扣Mbubuko.com,布布扣2bubuko.com,布布扣...Mbubuko.com,布布扣nbubuko.com,布布扣),κ?bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣  ?V,?opd,κ,obubuko.com,布布扣nbubuko.com,布布扣,(Mbubuko.com,布布扣i+1bubuko.com,布布扣...Mbubuko.com,布布扣nbubuko.com,布布扣),(Vbubuko.com,布布扣1bubuko.com,布布扣...Vbubuko.com,布布扣i?1bubuko.com,布布扣)??bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣  ?V,?opd,κ,obubuko.com,布布扣nbubuko.com,布布扣,(),(Vbubuko.com,布布扣1bubuko.com,布布扣...Vbubuko.com,布布扣n?1bubuko.com,布布扣)??bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣  bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣    ?Mbubuko.com,布布扣1bubuko.com,布布扣,?opd,κ,obubuko.com,布布扣nbubuko.com,布布扣,(Mbubuko.com,布布扣2bubuko.com,布布扣...Mbubuko.com,布布扣nbubuko.com,布布扣),()??bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣    ?Mbubuko.com,布布扣i+1bubuko.com,布布扣,?opd,κ,obubuko.com,布布扣nbubuko.com,布布扣,(...Mbubuko.com,布布扣nbubuko.com,布布扣),(Vbubuko.com,布布扣1bubuko.com,布布扣...Vbubuko.com,布布扣i?1bubuko.com,布布扣V)??bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣    ?Vbubuko.com,布布扣bubuko.com,布布扣,κ?bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣其中Vbubuko.com,布布扣bubuko.com,布布扣=obubuko.com,布布扣nbubuko.com,布布扣(Vbubuko.com,布布扣1bubuko.com,布布扣,...,Vbubuko.com,布布扣n?1bubuko.com,布布扣,V)bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣

函数调用

函数调用(MN)bubuko.com,布布扣 先计算Mbubuko.com,布布扣 的值,Nbubuko.com,布布扣 保存到continuation:

  ?(MN),κ?bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣?M,?arg,κ,N??bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣
Mbubuko.com,布布扣 计算完后从continuation取出Nbubuko.com,布布扣 计算(我们采用call-by-value的调用方式),同时保存Mbubuko.com,布布扣 的计算结果Vbubuko.com,布布扣
  ?V,?arg,κ,N??bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣?N,?fun,κ,V??bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣
Nbubuko.com,布布扣 也计算完后,进行βbubuko.com,布布扣 归约:
  ?V,?fun,κ,λX.L??bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣?L[XV],κ?bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣
这个地方很有意思,可以看到函数调用最后βbubuko.com,布布扣 归约的过程不会使continuation增长。 所有求值过程中,会导致continuation增长的几个过程是基本运算中对参数的计算过程、函数调用中对函数的计算过程以及对参数的计算过程。 一般也认为函数调用中函数的这个位置(也就是(MN)bubuko.com,布布扣 Mbubuko.com,布布扣 这个位置)也算参数位置, 所以判断一个函数调用是不是尾调用的依据是: 这个函数调用表达式是不是在一个参数位置,如果在参数位置,就不是尾调用。

上面分析的求值过程里增加了两种continuation:

  κbubuko.com,布布扣         bubuko.com,布布扣         bubuko.com,布布扣bubuko.com,布布扣=bubuko.com,布布扣|bubuko.com,布布扣|bubuko.com,布布扣bubuko.com,布布扣...bubuko.com,布布扣?arg,κ,N?bubuko.com,布布扣?fun,κ,V?bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣

代码实现

函数value-of/k是bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣 。 函数apply-cont是bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣 。 编写代码要注意对value-of/和apply-cont的调用都必须是尾调用。

过程bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣 的代码:

bubuko.com,布布扣

出于写起来方便的原因,使用函数来保存continuation。 用(end-cont)表示空的continuation mt。 (end-cont)只有在程序结束的时候才会运行一次。 这里让(end-cont)打印了个">> Done!",这个打印只会运行一次。 如果打印了超过一次,或者没打印,那么代码肯定有错。

过程bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣 的代码:

bubuko.com,布布扣

寄存器风格的代码实现

这小节换个方式写代码。 求值过程有两个状态量:当前计算的表达式和当前的continuation。 我们用两个全局变量the-exp和the-cont来保存这两个状态量。 使用全局变量后,函数value-of/k和apply-cont就不再需要参数。 另外,还需要一个全局变量来保存下一步是要进行bubuko.com,布布扣vbubuko.com,布布扣bubuko.com,布布扣 还是bubuko.com,布布扣cbubuko.com,布布扣bubuko.com,布布扣 。 这个全局变量叫the-pc。 这三个全局变量被称作寄存器(所以叫寄存器风格)。 当the-pc的值为逻辑假#f时,解释器运行结束。 现在解释器运行时就是不断的执行the-pc直到the-pc的值是#f。 mainloop是这个主循环的过程:

bubuko.com,布布扣

进入主循环的过程前要先初始化寄存器:

bubuko.com,布布扣 

过程value-of/k不再需要参数,用寄存器the-exp代替原来的exp1,the-cont代替原来的cont。 当然还有其他一些修改。代码如下:

bubuko.com,布布扣

bubuko.com,布布扣

过程apply-cont的修改和value-of/k类似。 代码如下:

bubuko.com,布布扣

bubuko.com,布布扣

思考

  1. 对宏展开过程translate和替换过程substitute做递归转迭代是否意义不大,为什么?  
  2. 加入continuation后call-by-name的调用方式下的求值过程和代码实现?

简单易懂的程序语言入门小册子(7):基于文本替换的解释器,加入continuation,重构解释器,布布扣,bubuko.com

简单易懂的程序语言入门小册子(7):基于文本替换的解释器,加入continuation,重构解释器

标签:style   blog   class   code   tar   ext   

原文地址:http://www.cnblogs.com/skabyy/p/3704849.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!