最近跟着(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. iOS重写和成员变量访问权限

    一.重写机制 1.覆盖父类的方法 2.对父类方法做进一步的补充 注意:父类声明过得方法,子类无需声明. * 子类如果重写了父类的方法: 1.父类的指针指向子类的对象,则调用方法时,调用的是子类的方法: ...

  2. load_basemap

    map = new Map("map", { //basemap: "satellite", //center: [-85.743, 38.256], //zo ...

  3. Flex学习笔记-使用MXML和一个AS事件监听器监听事件

    <?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="ht ...

  4. leetcode329

    public class Solution { bool[,] tags;//用于标记是否已经访问过,false未访问,true已访问 int[,] records;//用于标记以当前为起点的最长升序 ...

  5. Intellij IDEA编辑golang时无法加载系统GOPATH变量

    问题: 编译go项目时,报找不到包.从日志看,GOPATH与系统设置的不一致. 如何解决:系统的gopath路径,加到Project libraries中 参考:https://segmentfaul ...

  6. 机器学习进阶-图像基本操作-数值计算 1.cv2.add(将图片进行加和) 2.cv2.resize(图片的维度变换) 3.cv2.addWeighted(将图片按照公式进行重叠操作)

    1.cv2.add(dog_img, cat_img)  # 进行图片的加和 参数说明: cv2.add将两个图片进行加和,大于255的使用255计数 2.cv2.resize(img, (500, ...

  7. 正则表达式——WPF输入控件TextBox 限定输入特定字符

    概念: 正则表达式是对字符串操作的一种逻辑公式, 就是用事先定义好的一些特定字符.及这些特定字符的组合,组成一个“规则字符串”, 这个“规则字符串”用来表达对字符串的一种过滤逻辑. 目的: 给定一个正 ...

  8. Hive安装 和管理

  9. guava collection/cache初探

    写了上面一篇,看了点eventbus相关的guava代码后,发现里面用到了很多其他guava包里的方法,所以顺着看一下,比如之前用到的map都是guava自己的 Multimap:可以包含有几个重复K ...

  10. shell字符串基本操作

    shell脚本中一切变量皆字符串,所以必须掌握字符串的常用处理方法.比如获取字符串长度.获取字符串指定位置字符.替换字符串中的指定字符或者删除某些字符等操作. 1.字符串操作列表 (1)var=val ...