首页 > 代码库 > SICP 习题 (1.41)解题总结

SICP 习题 (1.41)解题总结

SICP 习题1.41 看似和周边的题目没有关系,突然叫我们去定义一个叫double的过程,其实这道题的核心还是高阶函数。


题目要求我们定义一个过程double,它以一个过程作为参数,这个作为参数的过程已经约定是一个单参数过程。double过程需要返回一个过程,所返回的过程将传入的过程应用两次。


举例说,如果我们有个过程叫(扇耳光 贱人),调用这个过程会扇贱人一个耳光。

那么(double 扇耳光)会返回另一个过程,这个过程没有名字,我们暂且叫他“扇俩耳光”吧,调用(扇俩耳光 贱人)就会扇贱人两个耳光了。

也就是说((double 扇耳光) 贱人)这样的调用会扇贱人两个耳光。


好,题目问我们(((double ( double double)) inc) 5)的结果是什么,其中inc方法会给传入参数加1.


要完成这道题,先看看double如何定义吧。


完全按照题目意思,定义的double如下:

(define (double f)
  (lambda (x) 
    (f (f x)))) 

为了测试,我定义了一个我自己的inc过程

(define (my-inc x)
  (+ x 1))

最后直接测试

(define test-it (((double ( double double)) my-inc) 5))

结果是21,也就是5+16,就是做了16次加一的操作。


为什么呢?


我们可以一步一步展开


;首先将不同的double标号,分别是double1 , double2, double3,这样比较清晰
(define step1 (((double1 ( double2 double3)) my-inc) 5))

;然后将(double2 double3)展开:
(define step2 (((double1 (lambda (x) (double3 (double3 x)))) my-inc) 5))

;将(lambda (x) (double3 (double3 x))) 命名为lam1:
(define (lam1 x) (double3 (double3 x)))

;这样step2就等同于下面的step3:
(define step3 (((double1 lam1) my-inc) 5))

;再将(double1 lam1)展开:
(define step4 (((lambda (x) (lam1 (lam1 x))) my-inc) 5))

;将my-inc代入step4中得lambda中:
(define step5 ((lam1 (lam1 my-inc)) 5))

;将里面的lam1还原回原来的定义:
(define step6 ((lam1 (double3 (double3 my-inc))) 5))

;将里面的(double3 my-inc)展开:
(define step7 ((lam1 (double3 (lambda (x) (my-inc (my-inc x))))) 5))

; 将step7里的lambda定义为lam2:
(define (lam2 x) (my-inc (my-inc x)))

;那么step7可以转换为:
(define step8 ((lam1 (double3 lam2)) 5))

; 再将step8中的(double3 lam2)展开得到step9:
(define step9 ((lam1 (lambda (x) (lam2 (lam2)))) 5))

;将step9中得lambda函数定义为lam3:
(define (lam3 x) (lam2 (lam2)))

;那么step9就可以转换成step10这样:
(define step10 ((lam1 lam3) 5))

; 将step10中的lam1恢复成原来的定义:
(define step11 ((double3 (double3 lam3)) 5))

;将(double3 lam3)展开:
(define step12 ((double3 (lambda (x) (lam3 (lam3 x)))) 5))

;将step12中的lambda函数命名为lam4:
(define (lam4 x) (lam3 (lam3 x)))

;则step12可以表示成step13这样:
(define step13 ((double3 lam4) 5))

;将(double3 lam4)展开:
(define step14 ((lambda (x) (lam4 (lam4 x))) 5))

;将5代入step14中的lambda过程中:
(define step15 (lam4 (lam4 5)))

;将lam4还原回原始定义:
(define step16 (lam3 (lam3 (lam3 (lam3 5)))))

;将lam3还原回原始定义:
(define step17 (lam2 (lam2 (lam2 (lam2 (lam2 (lam2 (lam2 (lam2 5)))))))))

;将lam2还原回原始定义:
(define step18 (my-inc (my-inc (my-inc (my-inc (my-inc (my-inc (my-inc (my-inc (my-inc (my-inc (my-inc (my-inc (my-inc (my-inc (my-inc (my-inc 5)))))))))))))))))

;结果就是21了:
(define step19 21)


以上的分析过程比较繁琐,不过也比较详细。


如果从抽象一点的层面来看的话,也可以用另外一种方法

考察以下方法:

(((double ( double double)) my-inc) 5)


double过程的作用是将任何方法嵌套调用两次。


而(double double)就是将double嵌套调用两次,结果就是将任何方法嵌套调用4次。

如果有(define four-time (double double))的话,fourtime过程将任何方法嵌套调用4次。

进一步看得话(double (double double))相当于(double four-time)。


相当于是(four-time (four-time x))


这里要特别注意,两次four-time的嵌套调用并不是4+4次,而是4*4次调用,就是16次调用。


习题1.41解题完成,这道题也可以很好地帮助同学们理解高阶函数,特别是高阶函数的嵌套。