最美丽的编程语言Scheme——前三章复习

今天这讲,我们将复习一下前三章学过的内容。我们可以试试以下几个问题,看看有没有好的解决方案。

 

1、请将下列表达式变换为前缀形式。

(5 + 4 + (2 - (3 - (6 + 4 / 5)))) / (3 * (6 - 2) * (2 - 7))

 

呵呵,这种问题,我们处理起来可以借用分治处理方法。

我们首先对整个表达式进行划分,这里比较明显的是一个除法操作将两个表达式隔开。因此,我们可以先把除法操作作为第一个分界点。

然后,我们可以分别对左子表达式和右子表达式进行求解。这里,左、右子表达式可以用顺序求值方法得到结果。

(/ (+ 5 4 (- 2 (- 3 (+ 6 (/ 4 5))))) (* 3 (- 6 2) (- 2 7))) ;Value: -37/150  

 

2、请定义一个过程,它以三个数作为参数,返回其中较大的两个数之和。

这个问题,我们用常规的思考方法,是对这三个参数两两比较,把较大的两个挑选出来。

如果我们用cond表达式的话一共有三种情况(假定三个参数是x,y,z):(x, y),(x, z),(y, z)。

那么我们可以用下列方法求解:

(define (proc x y z) (cond ((and (>= x z) (>= y z)) (+ x y)) ((and (>= x y) (>= z y)) (+ x z)) (else (+ y z)))) ;Value: proc 

当然,作为函数式编程语言的一个非常重要的特性就是递归的执行效率。由于FPL大多采用解释执行的方式,因此在进行递归时,不会使应用程序的栈溢出,这样我们就能大胆地使用递归,来简化表达式。下面就提供这个问题的递归解法:

(define (f x y z) (if (and (<= x y) (<= x z)) (+ y z) (f y z x) )) ;Value: f 

这个思路其实也很清晰。先尝试选出y和z,如果不满足情况,那么递归判断z和x,最后再判断x和y。

 

3、Ben Bitdiddle发明了一种检测方法,能够确定解释器究竟采用哪种顺序求值,采用应用序还是正则序。他定义了两个过程:

(define (p) (p)) ;Value: p (define (test x y) (if(= x 0) 0 y)) ;Value: test (test 0 (p)) 

如果是应用序求值会得到什么结果?正则序会得到什么结果?

如果是应用序的话,在调用test之前就会把(p)给计算出来,然后代入test中去计算。如果是正则序的话则相当于把test看作为一个宏,直接把(p)表达式代入到test中,等到要获得其结果时再做计算。

MIT-GNU-Scheme采用的是应用序,因此这个值是无法被求出的。如果是正则序的话我们应该获得结果0。

你可能感兴趣的:(编程,Scheme,语言)