今天这讲,我们将复习一下前三章学过的内容。我们可以试试以下几个问题,看看有没有好的解决方案。
1、请将下列表达式变换为前缀形式。
(5 + 4 + (2 - (3 - (6 + 4 / 5)))) / (3 * (6 - 2) * (2 - 7))
呵呵,这种问题,我们处理起来可以借用分治处理方法。
我们首先对整个表达式进行划分,这里比较明显的是一个除法操作将两个表达式隔开。因此,我们可以先把除法操作作为第一个分界点。
然后,我们可以分别对左子表达式和右子表达式进行求解。这里,左、右子表达式可以用顺序求值方法得到结果。
2、请定义一个过程,它以三个数作为参数,返回其中较大的两个数之和。
这个问题,我们用常规的思考方法,是对这三个参数两两比较,把较大的两个挑选出来。
如果我们用cond表达式的话一共有三种情况(假定三个参数是x,y,z):(x, y),(x, z),(y, z)。
那么我们可以用下列方法求解:
当然,作为函数式编程语言的一个非常重要的特性就是递归的执行效率。由于FPL大多采用解释执行的方式,因此在进行递归时,不会使应用程序的栈溢出,这样我们就能大胆地使用递归,来简化表达式。下面就提供这个问题的递归解法:
这个思路其实也很清晰。先尝试选出y和z,如果不满足情况,那么递归判断z和x,最后再判断x和y。
3、Ben Bitdiddle发明了一种检测方法,能够确定解释器究竟采用哪种顺序求值,采用应用序还是正则序。他定义了两个过程:
如果是应用序求值会得到什么结果?正则序会得到什么结果?
如果是应用序的话,在调用test之前就会把(p)给计算出来,然后代入test中去计算。如果是正则序的话则相当于把test看作为一个宏,直接把(p)表达式代入到test中,等到要获得其结果时再做计算。
MIT-GNU-Scheme采用的是应用序,因此这个值是无法被求出的。如果是正则序的话我们应该获得结果0。