SICP 习题(1.5)解题总结:应用序和正则序

来源:互联网 发布:区域生长分割算法 编辑:程序博客网 时间:2024/06/07 09:59

SICP的习题1.5 主要讲的是函数参数的求值方式,包括应用序和正则序。

解题前如果发现自己对应用序和正则序还不是太清楚,就需要重新看看1.1.5节“过程应用的代换模型”,对应用序和正则序有了较清楚的了解后解习题1.5就比较简单了。


先看看题目,题目讲的是一个叫Ben Bitdiddle的人发明了一种检测方法,可以确定解释器使用的使用那种求值序,就是判断解释器是使用应用序还是正则序求值。

他的方法是定义下面两个过程:

(define (p) (p))(define (test x y) (if (= x 0)        0       y))

然后执行下面的表达式:

(test 0 (p))


题目问我们,如果解释器是应用序求值会看到什么情况,如果是正则序又会看到什么情况。

如果对应用序和正则序理解比较透彻的同学可以直接读代码想到结果。

如果不是很清楚的话简单的方法就是在mit-scheme环境里试一下上面的过程。结果就是你的mit-Scheme环境“死机”了,就是没有反应了,原因是mit-Scheme使用的是应用序,当解释器求(test 0 (p))的值的时候会尝试求出参数0和参数(p)的值,参数0没什么好求的,已经是基本数字,参数(p)就不好求值了,解释器发现(p)是一个过程,执行它返回的结果还是(p),于是又求(p)的值,一直下去,子子孙孙无穷溃也,于是解释器就“死机”了。

更广泛地讲,所有Lisp解释器都采用应用序求值(参见SICP 1.1.5节结束部分,中文版第11页),所以以上过程执行的话在任何Lisp环境中都会让解释器“死机”的。


好,进一步想想,如果解释器是正则序会怎么样呢?如果是正则序的话,解释器先不去求参数的值,而是将参数替换到过程中去,将过程展开,接着看展开的结果中是否还有其他过程,有的话继续展开,将过程完全展开后再进行计算,然后根据计算结果归约。

对(test 0 (p)进行展开的话我们得到

(if (= 0 0) 0 (p))

好,现在的问题是,对于上面展开的过程应该怎么处理,是对if进行计算还是继续展开(p),如果是继续展开(p)的话也一样是“死机”了。

这时就要注意到题目下方括号部分有个假设,就是假设对于if的计算总是先判断条件是否成立,根据条件判断结果选择对应的表达式进行计算。

根据这个假设,对于(if (= 0 0) 0 (p)),只会计算0的部分,不会计算(p)的部分,所以这个表达式会返回0,而不是进入无限循环中。


以上是题目的解答,不过我个人对于正则序的理解有点不太一样,我直观的感觉是如果让我实现一个正则序的解释器,我会一直将过程展开,展开结束后才开始计算过程。这时的问题是if过程是否需要展开,如果对if进行展开的话又如何展开。所以我第一次做题目的时候想的结果是使用两种求值序都会让以上过程进入无限循环。当然,我是错的,因为我忽略了题目后面括号中的假设。


总结来讲,书中的这道题目是想让大家更清晰的理解应用序和正则序,所以大家也不需要纠缠于刚才讨论的细节,准确理解课程内容才是习题的目的。



原创粉丝点击