计算机程序的构造和解释(笔记)
chap3 模块化、对象和状态
章节说明
松耦合思想:将程序的变化尽量在比较小的局部范围内
两种策略:
面向过程设计: 处理的是系统的信息流
面向对象设计: 将系统看成一批对象,对象的行为可能随着时间的进展而变化
- 面向对象设计必须抛弃代换模型(见chap1.1),使用环境模型
- 如果有变发的话,流模式可以通过延时求值来松懈求值的顺序)(个人认为这里涉及设计模式的运行时依赖和编译时依赖,新手不是很懂(* ̄▽ ̄)y)
3.1 幅值和局部状态
这里说的是全局变量,幅值等。和C/C++不一样,Scheme中因为没有幅值= ,赋值反而变得另类有意思
3.1.1 局部状态变量
对于一个取金额的过程
(withdraw 25)
75
(withdraw 25)
50
(withdraw 60)
"Insufficient funds"
(withdraw 15)
35
全局环境变量
可以自由地被任何过程检查或修改
(define balance 100) ;balance 为全局环境变量
(define (withdraw amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance)
"Insufficient funds"))
其中:
在Scheme中,赋值是使用set!
语法为:
(set! ⟨name⟩ ⟨new-value⟩)
; <name> 为一个符号, <new-value>为任何表达式
; set 后面的!为一个命名习惯,意为改变变量值;类似谓词中的 ? 提醒
而对于
(begin ⟨exp1⟩ ⟨exp2⟩....⟨expk⟩)
则表示顺序求值,最后一个 <expk >表示返回的值
- 局部环境变量
在这里应该将balance 改为局部变量比较好,因为金额只有这个过程才可以修改
(define new-withdraw
(let ((balance 100)) ; banlance为局部变量
(lambda (amount)
(if (>= balance amount)
(begin (set! balance (- balance amount)) balance)
"Insufficient funds"))))
当然,这种效果,这里书上也提到了是 * 封装 *
3.1.2 引进赋值带来的好处
这里例子说的是一个随机数产生的过程,用的是蒙特卡罗方法
例子是为了说明一个现象:从一个复杂计算过程中一部分的观点看,其他部分都像是在随着时间的不断变化,它们因长期自己随时间变化的内部状态。
3.1.3 引进赋值带来的代价
我理解这里说的是类似做高中数学题的时候,方程化简和求解的区别吧
先说两个重要的基本概念
* 函数式程序设计 *:不用任何赋值的程序设计,如LISP
* 命令式程序设计*:广泛采用赋值的程序设计,如C/C++
这里书上说的主要是赋值会破坏“同一的东西可以相互替代的”-引用透明 的性质吧。
再说下其他的性质:
同一: 两个事物可以相互替代,在代换模型中适应
变化: 同一的另一面,适用于环境模型
命令式程序设计的缺陷:
也就是过程设计的程序的通病咯,注意逻辑的顺序性;
具体一点就是:带有赋值的程序将迫使人们去考虑赋值的相对顺序,以保证每个语句所用的是被修改变浓的正确版本。
PS: 这一点在并发会出现的问题