最近跟着(How to Write a (Lisp) Interpreter (in Python))使用python实现了一个简易的scheme解释器。不得不说使用python这类动态语言实现不要太方便。

解释器的核心实际就是2个部分:

  • eval 在环境里求值表达式
  • apply 将一个过程应用于一组参数

eval、apply 这两个规则描述了求值过程的核心部分,这是任何解释器的基本循环。在这一循环中表达式在环境中的求值被规约到过程对实际参数的应用,而这种应用又被规约到新的表达式在新的环境中的求值,如此下去,直到下降到符号(其值可以在环境中找到)或者基本过程(它们可以直接应用)。

接着我又尝试使用c++实现,由于c++没有python那么方便的list,我定义了一个抽象基类Type,让各种表达式作为它的派生类。过程还算顺利,只是在对过程求值环境的处理上烦了迷糊。

例如:

(define x (lambda (a) (lambda (b c) (+ a b c))))
(define y (x 1))
(y 2 3)

求值(x 1)为求值 (lambda (a) (lambda (b c) (+ a b c))) 作用于1的结果,返回(lambda (b c) (+ a b c)),同时具有环境a=1这个过程。

接着求值(y 2 3),实际是求值过程(x 1)作用于2 3的结果,那么求值环境呢? 显然是当前的b=2,c=3再加上procedure所具有的环境a=1,而不是在求值这个表达式时的环境x=... , y=... 。

再来看递归:

(define factor (lambda (n) (* n (if (= n 1) 1 (factor (- n 1))))))
(factor 3)

求值(factor 3) 时,带着n=3 环境,接着求值内部的(factor (- n 1)) 带着n=2 (从左到右为从内到外部环境,优先选择左侧),直到环境为 n=1时,(factor 1)返回1,在上层环境为n=2因此(* n 1)返回2,然后就是正常的递归回溯了。

以上说的可能有些混乱,简言之,求值一个过程时,环境为参数环境+过程的环境而不是参数环境+求值时的环境。

目前实现的解释器还很简易,缺少很多必要功能。例如垃圾回收,尾递归优化等。总之继续努力吧(__) 嘻嘻……

参考代码:https://github.com/CknightX/Practice/tree/master/c%2B%2B/scheme-interpreter

求值器本质--eval&apply的更多相关文章

  1. OpenGL学习笔记——求值器和NURBS

    http://codercdy.com/openglxue-xi-bi-ji-qiu-zhi-qi-he-nurbs/ 在最底层,图形硬件所绘制的是点.直线和多边形(通常是三角形和四边形).平滑的曲线 ...

  2. Aviator 表达式求值引擎开源框架

    简介¶ Aviator是一个高性能.轻量级的java语言实现的表达式求值引擎,主要用于各种表达式的动态求值.现在已经有很多开源可用的java表达式求值引擎,为什么还需要Avaitor呢? Aviato ...

  3. JavaScript忍者秘籍——运行时代码求值

    1. 代码求值机制 JavaScript中,有很多不同的代码求值机制. ● eval()函数 ● 函数构造器 ● 定时器 ● <script>元素 - 用eval()方法进行求值 作为定义 ...

  4. 利用Z.Expressions.Eval表达式求值

    Z.Expression.Eval是一个开源的(OpenSource),可扩展的(Extensible),超轻量级(Super lightweight)的公式化语言解析执行工具包. 使用方法:1.从n ...

  5. Python学习总结17:exec和eval执行求值字符串

    有些时候可能会需要动态地创造Python代码,然后将其作为语句执行或作为表达式计算. 1. exec >>>exec "print 'Hello, world!'" ...

  6. Stream01 定义、迭代、操作、惰性求值、创建流、并行流、收集器、stream运行机制

    1 Stream Stream 是 Java 8 提供的一系列对可迭代元素处理的优化方案,使用 Stream 可以大大减少代码量,提高代码的可读性并且使代码更易并行. 2 迭代 2.1 需求 随机创建 ...

  7. 【Scheme】元循环求值

    #lang scheme (require rnrs/base-6) (require rnrs/mutable-pairs-6) (define (eval exp env) (cond ((sel ...

  8. [SICP] 求值规则

    在Java语言学习中,通常不太关注求值规则. (2+4*6)*(3+5+7)这样的组合式的求值规则.通常归结为优先级问题: if.for等的求值规则通常归结为语义. 函数式编程语言的Scheme,将这 ...

  9. 延迟求值-如何让Lo-Dash再提速x100?

    「注释」作者在本文里没有说明这么一个事实: 目前的版本Lo-Dash v2.4.1并没有引入延迟求值的特性,Lo-Dash 3.0.0-pre中部分方法进行了引入,比如filter(),map(),r ...

随机推荐

  1. 新装Windows Server 2008 R2的设置

    原文链接:https://www.kafan.cn/edu/2898054.html 1.2008设置自动登录 具体方法:开始→运行→输入“rundll32 netplwiz.dll,UsersRun ...

  2. 24.纯 CSS 创作出平滑的层叠海浪特效

    原文地址:https://segmentfault.com/a/1190000014895634 感想:这里的波浪只是侧面的,利用几个平面一部分弧旋转得到. HTML代码: <div class ...

  3. <转载> bat 脚本基本语法 http://blog.csdn.net/bluedusk/article/details/1500629

        bat 脚本基本语法 2007-01-25 10:31 常用命令 echo.@.call.pause.rem(小技巧:用::代替rem)是批处理文件最常用的几个命令,我们就从他们开始学起. = ...

  4. zookeeper超时:Unable to connect to zookeeper server within timeout: 5000

    解决措施: 1:检查 提供方和消费方的address是否正确 <dubbo:application name="dubboxdemo-servive"/> <du ...

  5. 高程三 BOM 读书笔记

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...

  6. 1. 怎么设置可以使得虚拟机里面既可以访问主机也可以访问局域网而且是静态ip

    方法1: Bridged方式(桥接): (1). 虚拟机网络适配器设置为桥接 (2). 主机设置静态ip (3). 虚拟机也设置静态ip且和宿主机在同一网段 Bridged方式: 在图1中Networ ...

  7. pycharm 使用print不打印结果问题解决

    参考 http://blog.csdn.net/olfisher/article/details/52486368 参考2 http://www.imooc.com/qadetail/122734 问 ...

  8. delphi ios info.plist

    delphi ios info.plist delphi修改info.plist.TemplateiOS.xml文件,然后自动生成project1.info.plist http://docwiki. ...

  9. jsfl 常用方法

    //打开fla文档 fl.openDocument (JSFL_PATH+"tongzhi.fla"); //发布flash fl.getDocumentDOM().publish ...

  10. iOS开发 2x 3x图

    众所周知,iOS开发中的图片资源一般需要2倍图和3倍图,也就是2x,3x,但是最近思考了一个问题,为什么不能只提供3x的图片,2x的图片让系统从3x压缩就好了,于是上网搜索了下,得到了答案. 当我们在 ...