• SICP学习笔记(2.1.1 ~ 2.1.3)


                                                     SICP学习笔记(2.1.1 ~ 2.1.3)
                                                            周银辉

    这几节相对比较简单,主要引入“抽象”和“封装”等一些思想,作者花了不少笔墨想将“抽象”的思想注入到读者的头脑的,但如果先前学过一些面向对象编程的话,这几节就可快速通过了(除了2.1.3,此节的内容有些醍醐灌顶,稍后再说) 

    1,练习2.1

    按照题目的意思,“如果分母分子同号,则分子分母都化为正;否则,分子化为负,分母化为正”。我将这句话转换成了下面这句话“如果分母为负,则分子分母都取相反数;否则分子分母保持不变”,两句话是对等的,不信试试看:

    (define (make-rat n d)
      ;如果分母为负,则分子分母都取相反数
      (cond ((< d 0) (cons (- 0 n) (- 0 d)))
            ;否则分子分母保持不变
            (else (cons n d))))

    (define (num z)
      (car z))

    (define (den z)
      (cdr z))

    (define a (make-rat 2 3))
    (define b (make-rat -2 3))
    (define c (make-rat 2 -3))
    (define d (make-rat -2 -3))

    ;测试函数
    (= (num a) 2)
    (= (den a) 3)
    (= (num b) -2)
    (= (den b) 3)
    (= (num c) -2)
    (= (den c) 3)
    (= (num d) 2)
    (= (den d) 3)

    上面的输出全部是#t (True),说明正确哈。 

    2,练习2.2

    首先由序对构造点,然后由点构造线段,最后定义其他函数:

    (define (make-point x y)
      (cons x y))

    (define (x-point p)
      (car p))

    (define (y-point p)
      (cdr p))

    (define (print-point p)
       (newline)
       (display "(")
       (display (x-point p))
       (display ",")
       (display (y-point p))
       (display ")"))

    (define (make-segment a b)
      (cons a b))

    (define (start-segment s)
      (car s))

    (define (end-segment s)
      (cdr s))

    (define (mid-segment s)
       (let ((start (start-segment s))
             (end   (end-segment s)))   
         (make-point (/ (+ (x-point start) (x-point end)) 2)
                     (/ (+ (y-point start) (y-point end)) 2))))

    ;test
    (print-point (mid-segment (make-segment (make-point 2 3) (make-point 4 5))))

    输出为 (3,4)

    3, 练习2.3
    求矩形周长和面积,直接略过了哈,比较简单。

    4,数据意味着什么?

    关于2.1.3,真的很想总结出点什么,但真的不知道如何总结,正如作者在脚注中所言“令人吃惊的是,将这一思想严格地形式化却非常困难”,只默默地建议仔细地通篇阅读,的确让“每天都在吼面向对象的我们”有些醍醐灌顶,正如用如下方式来定义序对(Pair)一样:
    class Program
       {
           static void Main(string[] args)
           {
               var pair = MakePair(2, 3);

               Console.WriteLine(GetFirstElement(pair));
               Console.WriteLine(GetSecondElement(pair));
               DisplayPair(pair);

               Console.Read();
           }

           public delegate object PairDelegate(bool flag);

           public static PairDelegate MakePair(object a, object b)
           {
               return (flag) => { return (flag ? a : b); };
           }

           public static object GetFirstElement(PairDelegate pair)
           {
               return pair(true);
           }

           public static object GetSecondElement(PairDelegate pair)
           {
               return pair(false);
           }

           public static void DisplayPair(PairDelegate pair)
           {
               Console.WriteLine("( "+ GetFirstElement(pair) +" , "+ GetSecondElement(pair)+" )");
           }
       }

    5,练习2.4

    (define (cons2 x y)
      (lambda (m) (m x y)))

    (define (car2 z)
      (z (lambda (p q) p)))

    (define (cdr2 z)
      (z (lambda (p q) q)))

    ;test
    (define a (cons2 3 5))
    (car2 a)
    (cdr2 a)

    为了避免和系统预定义的标识符发生冲突,我将cons car cdr 后面都加了一个2。
    要解此题关键在(lambda (m) (m x y)) 应该注意到这里的m应该是一个过程,而非普通变量。所以对(define (cons2 x y) (lambda (m) (m x y))) 的理解就应该变成“所谓cons2,就是它接受一个过程,并将该过程应用到参数x和y”。那么要定义car2,则应该“传入一个过程,该过程会接受两个参数,并且返回第一个参数”,同理,要定义cdr2,则应该“传入一个过程,该过程会接受两个参数,并且返回第二个参数”。

    6,练习2.5

    如果 (2^a) * (3^b) = z, 求 a 和 b

    这个题比较有意思,表面上看一个二元方程只有一个表达式,貌似求不出来。这这个题的中幂底数比较巧合:一个奇数和一个偶数。所以,对于求a,如果m为奇数的话,那么a一定为0,否则 a = a‘ + 1, 其中a‘是 (2^a‘) * (3^b) = z/2的解,所以代码如下:

    ;定义 a^n
    (define (pow a n)
      (define (pow-inner a counter result)
        (if (= 0 counter)
            result
            (pow-inner a (- counter 1) (* result a))))
      (pow-inner a n 1))

    ;定义序对
    (define (cons2 a b)
      (* (pow 2 a) (pow 3 b)))

    ;定义car
    (define (car2 z)
      (if (= (remainder z 2) 0)
          (+ 1 (car2 (/ z 2)))
          0))

    同理,如果 z 除以3的余数不为0,那么b一定为0,否则 b = b‘ + 1, 其中 b‘ 是(2^a) * (3^b‘) = z/3的解。

    ;定义cdr
    (define (cdr2 z)
    (if (= (remainder z 3) 0)
         (+ 1 (cdr2 (/ z 3)))
         0))

    7,练习2.6

    SICP学习笔记(1.3.2 ~ 1.3.3)的“lambda计数”中已经给出答案了,跳转到那里去找答案吧。

    注:这是一篇读书笔记,所以其中的内容仅属个人理解而不代表SICP的观点,并随着理解的深入其中的内容可能会被修改


  • 相关阅读:
    使用超酷的jQuery缩略图生成插件NailThumb制作漂亮的缩略图web应用
    极客Web前端开发资源大荟萃#015
    极客编程小挑战#29:实现手机上常见的某一功能的效果显示
    在线制作gif loading图
    极客标签二重大礼华丽登场 宅男宅女必备套装
    SVG矢量图形课程基础入门篇
    浏览器JS交互,点击查询
    11选5专家投注研究算法
    大龙VBox API参数插件
    利用DLL劫持内存补丁技术注入
  • 原文地址:https://www.cnblogs.com/zhouyinhui/p/1588772.html
Copyright © 2020-2023  润新知