Program Structure 笔记14 (scheme解释器工作原理)

Program Structure 笔记14 (scheme解释器工作原理)

  (作者:colinboy  Email:cybbh@163.com) 2008.6.2

(内容难免出现错误或一些专业词汇使用不当,只是个人笔记,能理解总体内容就好)

 

在理解了deep list之后,我们可以理解更多关于解释器工作的内容.

 

理解scheme解释器的原理可以更好的理解求值模型,如应用序和正则序.

 

下面定义了一个scheme解释器的概括结构:

 

;接收输入然后计算

(define (scheme)

   (display ">")

   (print (eval (read)))

   (scheme))

 

;计算各子表达式的值然后调用apply执行过程调用.

(define (eval exp)

   (cond ((self-evaluating? exp) exp))

         ((symbol? exp) (look-up-global-value exp))

         ((special-form? exp) (do-special-form exp))

   (else (apply (eval (car exp))

                (map eval (cdr exp))))))

 

; 调用过程

(define (apply proc args)

   (if (primitive? proc)

       (do-maigc proc args)

       (eval (substitude (body proc) (formals proc) args))))

 

我们发现此解释器的结构和以前实现的简单求值器的结构十分类似,他们之间的区别为求值器只有2种类型的表达式,一种为数字,一种为操作符号(+ - * /),而此解释器有4种类型的表达式,分别为自求值表达式(类似java中的基本类型或者c中的int char等类型),符号(一般为变量名或者过程名等),特殊形式调用(define,if,cond,lambda,let)和过程调用.

 

自求值表达式包括数字,布尔常量和字符串,34,#t,#f,"myname".

 

自求值表达式和符号为单个数据的形式,34, pi, 特殊形式调用和过程调用为list类型的表达式,一般一个过程调用存储为一个list,(do-something x y z).

 

eval,四种表达式的处理为:

((self-evaluating? exp) exp)) 如果表达式是一个自求值类型,那么就返回此表达式.

((symbol? exp) (look-up-global-value exp))  如果表达式是一个符号,就在全局环境中查找此符号所对应的值,然后返回此值.

 

((special-form? exp) (do-special-form exp)) 如果表达式是一个特殊形式的调用,那么就进行特殊形式表达式的求值....

 

(else (apply (eval (car exp)) (map eval (cdr exp))))))  最后,如果表达式是一个普通的过程调用,就首先计算出此过程名对应的值(每个过程都是一个值,例如c语言中有函数的指针,这个指针指向一个值,即函数的入口地址),然后计算所有的实际参数表达式,之后调用apply执行过程.所以这个解释器是一个实现了应用序求值的解释器.

 

apply,对于过程调用分为2中情况:

(if (primitive? proc)

       (do-maigc proc args)

       (eval (substitude (body proc) (formals proc) args)))

 

调用的过程是primitive,即语言内置的,那么就直接调用此过程.

如果调用的过程不是primitive,那么过程就是用户自定义的,首先调用substitude对过程体内的形式参数使用实际参数进行替换,然后再根据替换后的结果调用eval计算此过程.

 

例如以下的调用:

((lambda (a b) (+ (* 2 a) b)) 6 7)

formals对应(a b).

body(+ (* 2 a) b).

 

调用substitude的参数为:

(substitude '(+ (* 2 a) b) '(a b) '(6 7))

过程执行后为把第一个参数中的ab替换成67.

 

替换后的结果为(+ (* 2 6) 7)

 

 

根据上面的解释器结构,我们实现一个简单的scheme解释器.使用了替换模型(substitution model),没有实现define过程.

 

;循环接收输入后计算

(define (scheme-1)

  (display "Scheme-1: ")

  (flush)

  (print (eval-1 (read)))

  (scheme-1))

 

;接收表达式,根据应用序规则计算子表达式的值

(define (eval-1 exp)

  (cond ((constant? exp) exp)

     ((symbol? exp) (eval exp))  ;使用了scheme中的eval计算全局环境中符号的值.

     ((quote-exp? exp) (cadr exp))

     ((if-exp? exp)

      (if (eval-1 (cadr exp))

          (eval-1 (caddr exp))

          (eval-1 (cadddr exp))))

     ((lambda-exp? exp) exp)

     ((pair? exp) (apply-1 (eval-1 (car exp))      ;计算过程

                    (map eval-1 (cdr exp))))

     (else (error "bad expr: " exp))))

 

;调用过程进行计算

(define (apply-1 proc args)

  (cond ((procedure? proc) 

 (apply proc args))   ;使用了scheme中的apply来计算primitive的过程调用.

((lambda-exp? proc)

(eval-1 (substitute (caddr proc)   ;过程体

                   (cadr proc)    ;形式参数

                   args           ;实际参数

                   '())))

     (else (error "bad proc: " proc))))

 

 

;一些辅助过程

(define (constant? exp)

  (or (number? exp) (boolean? exp) (string? exp) (procedure? exp)))

 

(define (exp-checker type)

  (lambda (exp) (and (pair? exp) (eq? (car exp) type))))

 

(define quote-exp? (exp-checker 'quote))

(define if-exp? (exp-checker 'if))

(define lambda-exp? (exp-checker 'lambda))

 

; substitute的实现

(define (substitute exp params args bound)

  (cond ((constant? exp) exp)

     ((symbol? exp)

      (if (memq exp bound)

          exp

          (lookup exp params args)))

     ((quote-exp? exp) exp)

     ((lambda-exp? exp)

      (list 'lambda

            (cadr exp)

            (substitute (caddr exp) params args (append bound (cadr exp)))))

     (else (map (lambda (subexp) (substitute subexp params args bound))

            exp))))

 

(define (lookup name params args)

  (cond ((null? params) name)

     ((eq? name (car params)) (maybe-quote (car args)))

     (else (lookup name (cdr params) (cdr args)))))

 

(define (maybe-quote value)

  (cond ((lambda-exp? value) value)

     ((constant? value) value)

     ((procedure? value) value)

     (else (list 'quote value))))

 

测试:

STk> (scheme-1)

Scheme-1:

((lambda (a b) (+ (* 2 a) b)) 6 7)

19

 

由于我们没有define过程,所以想定义一些递归过程将变得有点困难,下面是一个不使用define创建的递归过程.完成的功能为计算阶乘.

Scheme-1:

((lambda (n)

  ((lambda (f) (f f n))

    (lambda (fact n)

       (if (= n 0) 1

           (* n (fact fact (- n 1)))))))

             5)

120

 

此解释器的2个核心过程:

eval-1接收一个表达式然后返回此表达式的计算结果.

apply-1接受一个过程和一个实际参数列表,然后调用过程.

 

eval-1apply-1不命名为evalapply是为了避免和scheme内置的evalapply产生冲突.

 

eval-1的说明:

此解释器有4种基本表达式:

1.自求值表达式

2.符号(变量).

3.特殊形式(在此实现中,只包裹了quote,iflambda).

4.过程调用(可以进行primitive过程的调用和lambda产生的过程的调用).

 

在此解释器实现中,lambda表达式的值就为此lambda表达式.

 

 

apply-1的说明:

2种类型的过程:primitive和使用lambda创建的.

 

substitute的说明:

对于如下过程:

((lambda (x y)

((lambda (x) (+ x y))

(* x y)))

5 8)

 

过程的"":

((lambda (x) (+ x y))

(* x y))

 

我们要把x替换为5,y替换为8,替换结果为:

((lambda (x) (+ x 8))

(* 5 8))

 

注意结果不是:

((lambda (5) (+ 5 8))

(* 5 8))

 

因为(lambda (x) (+ x 8)中的x不是最外层lambda语句的参数,而是内部lambda的参数,是受到约束的.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值