Program Structure 笔记11 (简单scheme求值器的实现)

Program Structure 笔记11 (简单求值器的实现)

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

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

 

我们要实现一个求值器,能计算类似下面的表达式:

(+ 1 2 3 4 5)

(+ 1 (+ 2 3) 4)

(+ (+ 1 2) (* 3 4))

 

此求值器只实现了+ - * /四种基本运算.

 

简单求值器完整代码:

;Read and print loop

(define (calc)

   (display "Calc: ")

   (flush)

   (print (calc-eval (read)))

   (calc))

 

;Evaluate an Expression

(define (calc-eval exp)

(cond ((number? exp) exp)

          ((list? exp) (calc-apply (car exp) (map calc-eval (cdr exp))))

    (else (error "oh my god!" exp))))

 

;Apply function to some arguments.

(define (calc-apply fn args)

   (cond ((equal? fn '+) (accumulate + 0 args))

         ((equal? fn '*) (accumulate * 1 args))

         ((equal? fn '-) (cond ((null? args) (error "bad args!"))

                               ((= (length args) 1) (- (car args)))

                               (else (- (car args) (accumulate + 0 (cdr args))))))

         ((equal? fn '/) (cond ((null? args) (error "bad args!"))

                               ((= (length args) 1) (/ (car args)))

                               (else (/ (car args) (accumulate * 1 (cdr args))))))

   (else (error "bad operator"))))

 

测试:

STk> (calc)

Calc: (+ 1 2)

3

Calc: (* 2 (+ 1 2))

6

Calc: (/ 2)

0.5

 

此求值器的结构为:

1.      calc,循环执行,calc接受输入表达式然后传递给eval.

2.      eval,把输入的表达式转换成apply调用.

3.      apply,根据传入的操作符和参数计算出结果.

 

在第一部分中,有个(read)调用,read是读入用户输入的数据,例如用户输入:

(+ 1 (+ 2 3) 4)

read会把输入的数据组织成一个list,对于上面的输入,产生的list(+ 1 + 2 3 4).

 

我们可以编写一个测试read的函数

(define (readinf inf)

   (if (null? inf) '()

       (se (car inf) (readinf (cdr inf)))))

 

测试如下:

执行 (readinf (read))

输入:(+ 1 2 (* 3 4) (/ 5 6) 7)

输出:(+ 1 2 * 3 4 / 5 6 7)

 

执行(readinf (read))

输入: (+ '1 '2 (/ 3 4) '5)

输出: (+ quote 1 quote 2 / 3 4 quote 5)

 

对于'1这样的输入,会首先读入',然后读入1.

 

其实read并不会计算任何表达式的值,它仅仅只是按照输入的字符读入然后存储到表中,对如+这种操作符只是当作'+字符处理.

 

read不会存储括号,而是忽略掉,对于如(+ 1 2 (* 3 4) (/ 5 6) 7)这种输入,read读入后组成sentence(+ 1 2 * 3 4 / 5 6 7).

 

eval的作用为把输入的表达式中的参数计算成值.

 

((list? exp) (calc-apply (car exp) (map calc-eval (cdr exp))))这句表示调用apply,并且遵循应用序的规则.

所以我们实现的求值器是一个应用序的求值器!

 

对于如(+ (+ 1 2) (+ 3 4) 5), 调用apply,第一个参数为'+,第二个参数为一个表,内容为所有参数的值.所以在执行此次调用之前会首先计算出(+ 1 2)(+ 3 4),然后再把计算出的值作为参数计算出最后的结果.

 

我们实现的求值器并不和scheme的求值器一样,因为在scheme的求值器中,调用apply的第一个参数为一个函数,而不是像我们实现的这种为一个字符.

 

但是此求值器的结构是和scheme的求值器十分类似的.

 

仔细观察我们发现,calc没有遵循函数式程序设计规则,因为每次调用calc,可能会产生不同的结果.(例如第一次调用计算的是(+ 1 2),而第二次调用计算的是(+ 3 4),就会产生不同的结果).

 

但是calc-evalcalc-apply是遵循函数式程序设计规则的.

 

一些自求值的表达式:

'1

1

#t

#f

"string"

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值