oakland / tecblog

My tech blogs
4 stars 0 forks source link

读书笔记:SICP #66

Open oakland opened 6 years ago

oakland commented 6 years ago

B 站搜 SICP 有资源,真的是太厉害了我的 B 站,啥都有! 网上还有一个 python 版本的:http://www-inst.eecs.berkeley.edu/~cs61a/sp12/book/

sicp 关于“层”的概念

sicp 中关于层的概念很有意思,其实对于写代码和组织代码结构有很好的指导意义。非常有意思。就是每一层只负责考虑本层的内容,这一层的基础构成了一个复杂的内容,这个复杂的内容又是更高级一层的基础元素。这个概念很有意思,也对于指导写代码有很好的指导建议。

勘误

中文版翻译有误。 17页,1.1.8过程作为黑箱抽象的第一段第一句话的翻译有误。“...一组手工定义...”,原文是 'mutually' 应该是互相定义,而不是手工定义,应该是当做 mannully 去翻译了。 出版社有勘误表,可以联系出版社把勘误发过去。

终于开始读 sicp 了

It should be clear that the possibility of associating values with symbols and later retrieving them means that the interpreter must maintain some sort of memory that keeps track of name-object paris. This memory is called the environment...

上面这句话说了什么叫做环境。

In programming, we deal with two kinds of elements: procedures and data.(Later, we will discover that they are really not so distinct).

1.1.4 Compound Procedures 这一小节讲解的关于 square, sum-of-square 以及 (define (f a) ( sum-of-square (+ a 1) (* a 2) )) 的这个例子很好的说明了编程分层的概念,并且很好的说明了一个函数,或者说一个 procedure 是如何从简单演化为复杂的过程的。square 是对乘法这个简单函数的应用之后形成的复杂函数,sum-of-square 是对 squre 的应用之后形成的复杂函数,而 f 函数则是对 sum-of-square 的应用,毕竟 sum-of-square 是除了带有抽象参数之外,还有具体内容函数,比如里面会有 1, 2 这些具体的数字。所以我觉得 square 和 sum-of-square 的抽象程度高于 f 函数。f 函数更像是对 sum-of-square 的应用,而 square 和 sum-of-square 看起来更抽象。 再说程序分层的概念,还是刚才的例子,很好的解释了什么叫程序分层:分层就是上面一层依赖于下面一层,而下面一层是上面一层的基础。我们与其构造一个复杂的物体,不如先构造一些简单的物体形成基础,然后通过对基础的组合和应用,形成高层的复杂东西。这就是程序分层的概念。square 依赖于 “乘法” 这个简单的函数或者说计算方式,sum-of-square 依赖于 square,f 依赖于 sum-of-square,最终 “乘法” 这个简单的计算方式通过三层的构造形成了一个相对复杂的 f 函数。而每一层对于我们而言,都是好理解的。这就是分层,每一层的逻辑都非常清楚,但是每一层的元素又是从地下一层获取来的。当然,分了三层,我们也能够快速的读懂 f 函数的意义是因为,我们对于 sum-of-square 有着天然的理解,这当然归功于我们从小学到高中受到的数学教育,这种理解已经演化成了我们的潜意识,让我们可以快速的理解 f 函数的意义。如果我们没有这种潜意识,你就会发现,这个函数还是有一定的复杂性的。所以很多时候我们不理解一个大神写的框架,或者一个库的时候,往往是我们没有理解他的底层的内容,如果你已经把底层的东西理解的很透彻,而且形成了一种像潜意识一样的东西的时候,你对于上层东西的理解会是水到渠成的。当然如果层分的太多,有可能理解起来会需要深入到底层然后再上到顶层,这个过程本身也会变得复杂。所以分层总的来说还是有利于编程的,但是过多的层,可能会导致程序理解起来会更加复杂。上面的例子中乘法是最底层的基本东西,而和乘法有关的还有 加减除 这些最基本的概念,他们都可以通过一层一层堆叠的方式,形成复杂的东西。这就是我理解的分层。 再说说抽象。我们常说抽象,这个词本身就太抽象,因为抽象包含的意义实在太多了。那么我个人觉得与其说抽象,不如说简化,抽象就是把一个事物最本质的东西提取出来的过程,而把最本质的东西拿出来的过程,就是去掉一些繁琐装饰和多余细节的过程,而这个过程实际上就是简化!所以,SICP 通篇在讲 abstraction,我觉得可以把 abstraction 理解成 “简化”。抽象即简化。

SICP 越看越有意思,实际上很多东西讲的都是最基本的东西,但是往往这些基本的东西能给你带来极大的启发。复杂的东西不过是复杂的事物以简单的规律运行的,很多时候我们只看到了复杂事物的复杂,却忽略了它运行规律的简单。

SICP 我现在很愿意往下看,而且看的速度也会越来越快。就和三国演义一样,最开始看的时候特别无聊,但是越看越精彩!


打算结合 youtube 上 SICP 的视频一起看,结合起来看效果不错。

视频里,老师说的是最重要的控制系统的复杂性。因为计算机程序会变得异常庞大,非常非常庞大,如果不控制复杂性的话,实际上你是完全无法通过花费时间来理解这个复杂内容的。我们能够 hold 住一个庞大的计算机系统可能性在于,我们拥有控制系统复杂性的技术(techniques for controlling the complexity of these large systems)。如果我们没有这些技术的话,我们实际上就无法去理解和控制一个庞大的系统。 而实际上,控制复杂性的技术才是计算机科学的本质。


1.2 Procedures and processes they generate

这里 procedures 表示的朝着每个结果所要做的动作,而 processes 表示每个动作所产生的一个状态,这个状态是逐渐向最终结果靠拢的。

We have now considered the elements of programming: We have used primitive arithmetic operations, we have combined these operations, and we have abstracted these composite operations by defining them as compound procedures. But that is not enough to enable us to say that we know how to program. Our situation is analogous to that of someone who has learned the rules for how the pieces move in chess but knows nothing of typical openings, tactics, or strategy. Like the novice chess player, we don’t yet know the common patterns of usage in the domain. We lack the knowledge of which moves are worth making (which procedures are worth defining). We lack the experience to predict the consequences of making a move (executing a procedure).

上面这段话也蛮有启发性,我翻译一下: 到目前为止,我们已经考虑到了和变成相关的所有要素:最基础的数学操作符,这些基本操作的组合,以及通过把他们定义为复合过程而抽象出来的复合操作。我们现在就像是一个知道如何在棋盘上移动各个棋子的初级棋手,但是我们并不知道下次的技巧和策略。我们不知道下棋时常用的模式。我们缺乏经验:到底走哪一步棋是值得的(即计算机中,那个过程是值得定义的)。我们也缺乏预测某一步棋产生的结果的经验(即执行那个过程会产生什么样的结果的经验)。

我翻译的并不好,但是翻译一遍,还是有助于理解的。我觉得还是看上面这段英文更具有启发性。值得仔细品味。


感觉计算机实际上要比数学更回归底层,比如数学中定义阶乘: n! = n (n - 1) (n - 2) ...3 2 1 这对于 “人” 而言是可以理解的,但是对于“计算机”而言,如果你这么定义,计算机是不会理解的。因为中间的省略号人可以理解,但是计算机无法理解,所以你需要把这个定义的根本意义和根本计算方法表达出来。这就是我理解的计算机比数学更底层的意思。对于计算机而言,上面的定义依然是带有抽象性质的。计算机很傻,它只会帮你快速的做重复而简单的工作,所以你需要把这种抽象再具体化成一个过程(procedure)才能让计算机执行和理解。

  1. Metalinguistic Abstraction

    In our study of program design, we have seen that expert programmers control the complexity of their designs with the same general techniques used by designers of all complex systems.

程序的设计其实就是控制程序的复杂度。

如何安装 mit/gnu

通过这个 so的回答安装好,输入 scheme 然后回车。通过 ctrl + c 然后输入 q 可以退出。 命令行中直接输入 (quit) 也可以退出。

refer

Modularity, Objects and States

In addition to making programs more modular, concurrent compu- tation can provide a speed advantage over sequential computation. Se- quential computers execute only one operation at a time, so the amount of time it takes to perform a task is proportional to the total number of operations performed.34 However, if it is possible to decompose a problem into pieces that are relatively independent and need to com- municate only rarely, it may be possible to allocate pieces to separate computing processors, producing a speed advantage proportional to the number of processors available.

上面这段话说了 concurrency 的本质和 modularity 的本质,讲的很好。

To quote some graffiti seen on a Cambridge building wall: “Time is a device that was invented to keep everything from happening at once.”

上面这句话太有意思了,时间的本质是什么,就是所有的事情都只能发生一次。因为即使是同一件事情,因为时间不同,那么也无法是同一件事情。

关于使用 cons 和 car, cdr 构建有理数的例子

教授说 we're separating the use of something with the representation of something

关于 generic operators

这部分的内容不是很复杂,不过在 4b 26:30 左右的时候老师说了一下,这个 strategy 的名字叫 Dispatch on type,感觉这个和 redux 的理念很像。也是 dispatch 和 type。

chain of types

decentralized control

A simulator for digital circuits

这部分的内容中又出现了 dispatch,而且这个 dispatch 中还有 get, set 等的操作,感觉很像 redux 的内容,实际上我觉得 redux 应该也是借鉴了这个的 idea。

Stream

开头老师就说了,我们不仅仅要开始关注 value,还要开始关注 time 了。这个其实就是关于同步异步,或者说多进程的问题了。

We can't just think our program to be mathmatically, but physically.

就是单纯的数学的思考方式已经无法解决问题了,我们需要引入物理的思考方式。

dynamic binding

7b 的中间部分讲了动态绑定,非常有意思,这个例子对于我之前理解的动态绑定和静态绑定有很好的帮助。 7b 还讲了一个按值传递和按引用传递的概念,也非常有意思。这个说的是 by name or by value,by name 实际上就是 delay 了。 7b 还讲了一个 thunk 的概念!我的天啊,这个简直就是太牛逼了。原来 thunk 是从这里来的。就是延迟求值的意思。

prolog

sicp 真的是关于所有语言的书,是关于编程本质的书。这里面介绍了很多中语言风格,比如这个 prolog 语言就很神奇,也是一种特殊的编程方式。所以为了体验不同语言的风格,我打算学习学习多种原因,比如 prolog

语言的三要素? primitivies means of combination means of abstraction

这三点在整个课程的过程中老师一直在强调。

递归其实就是不停的进入自己,转换成便利的方式其实就是从内部向外部。递归则是从外部向内部,最后再反过来。

7a 中的 fixed point 部分没看懂

需要问一下 gyd,或者现在网上查查资料,实在是没有理解什么意思。

9a explicit evaluator

eval 的过程是把内容填充到 stack 的过程,而 apply 的过程是把 stack 的内容应用的过程,也就是 pop stack 的过程。

10a compilation

evaluator 尽可能的保存所有可能用到的内容,但是 compilation 已经分析过一边代码了,把无关的操作都去掉了,直接拿到需要执行的操作。

others

https://stackoverflow.com/questions/4266733/short-explanation-of-last-two-chapters-of-sicp

oakland commented 2 years ago

https://codology.net/

sicp 习题答案

oakland commented 2 years ago

2.3.4 Example: Huffman Encoding Trees For example, the ASCII standard code used to represent text in computers encodes each character as a sequence of seven bits. Using seven bits allows us to distinguish 2^7, or 128, possible different characters. In general, if we want to distinguish n different symbols, we will need to use log2n bits per symbol. If all our messages are made up of the eight symbols A, B, C, D, E, F, G and H, we can choose a code with three bits per character.

通过 1 或者 0 来代表符号,想要代表的符号的数量,可以用 log2n 位的 1 或者 0 来代替。

这个例子中为什么 a 的 frequency 是 8 ,没看懂,不应该是 9 吗?