计算机程序的构造和解释(第二版)
- define
- cond
- if (else)
- special form,不能实现为对cond的封装(why?)
- and or not
- sqrt
- 形参应该可以统一换名:‘作弊检测程序’?
- 内部定义:嵌套的define(块结构)
- 词法作用域:内部程序共享的变量可以作为自由变量
- 线性递归(gcd)
- 尾递归(Scheme解释器必须支持TCO)
- 树状递归(fib)
- 灵巧的编译器:--> 迭代形式(参考TLS:关键是推断出额外的语义变量?)
- Lame定理:如果gcd需要k步计算m,n的最大公约数,则min(m,n)>=Fib(k)
- 能够骗过Fermat检查的称Carmichael数,561 1105 1729 2465 ...
- Miller-Rabin检查
- lambda
- let
- fixed-point:guess-next
- (cont n d k):连分式
- 第一级过程:必须为自由变量分配空间
- 序对(tuple?):可用cons、car、cdr来实现
- (cons x y)返回的值是一个过程,作用于0得到x?
- 区间:make-interval
- 数值计算的精度问题
- list
- map
- for-each:不收集结果
- 层次式数据结构:
- cons作用于list
- ‘序列’抽象
- (define (filter predicate sequence) ...
- (define (accumulate op initial sequence) ...
- --> fold-left/right
- 多项式求值:Horner规则(最优) A.M.Ostrowski, 1954
- flatmap?map的结果再包一层accumulate
- queens:为什么flatmap里交换参数顺序会使计算很慢?
- e.g. 一个图形程序(分形?) transform-painter
- 符号数据:'
- 引入特殊形式quote恢复语言的一致性
- deriv 求导
- e.g. 集合
- intersection-set
- 集合作为二叉树(应该是说‘用二叉树实现集合’吧):
- element-of-set?(归并树)
- (adjoin x set)
- lookup
- e.g. Huffman编码树
- 抽象数据的多重表示
- complex
- 数据导向的程序设计:基于类型的dispatch?转换表?
- apply-generic:在复杂类型层次中的搜索。。。
- e.g. 符号代数
- 多项式计算
- GCD计算是所有需要完成有理函数操作的系统的核心
- 概率方法:Richard Zippel,1979
- 对于系统结构2种不同的‘世界观’:对象、流
- account:withdraw
- set!
- begin?
- rand:random-init rand-update
- p159 代数互换的本质是,符号不过作为值的名字 ...
- ‘同一’的可以相互替换:引用透明性
- 使用‘赋值’的命令式程序:强迫人们去考虑赋值的相对顺序,以保证变量更新的都是正确的版本
- ?一个环境就是框架(frame)的一个序列 —— Stack frame?
- 求值的代换模型 => 求值的环境模型(自底向上?自顶向下?)
- set-car! set-cdr!
- + get-new-pair 可实现cons操作
- 队列(front,rear)
- table?一维、2维、任意维
- memoize
- e.g. 数字电路的模拟
- half-adder
- full-adder
- make-wire
- get-signal
- add-action!
- after-delay 待处理表
- 约束传播:约束系统、连接器
- 并发
- 串行化
- parallel-execute
- make-serializer:确保parallel-execute不会交错执行(同步互斥锁?)
- mutex
- test-and-set!
- 屏障同步:PowerPC指令sync eieio
- ×在本质上看,在并发控制中,任何时间概念都必然与通信有内在的密切联系
- 串行化
- 流
- p221 从表面上看,流也就是表(#see Haskell type class?)
- stream-car cons-stream stream-filter stream-map ...
- delay force
- p252 交错级数的加速序列?
- P255 interleave?无穷流?
- integral 积分电路?
- e.g. 。。。为什么是信号处理???
- p244 ML的多态数据类型?
- p245 随机数的流
- (define random-numbers (cons-stream random-init (stream-map rand-update random-numbers)))
- Cesaro试验?monte-carlo过程计算pi?
- 用流模拟一个变化的量?(Haskell的IO Monad?)
- 并发:流的‘归并’?
- 元语言抽象:构造自己的求值器(解释器)
- 标准Scheme:顺序求值的限制
- 正则序求值?
- 不确定顺序?
- 元循环:用被求值的语言写出的此语言的求值器
- 模型:实际表现为eval和apply的相互作用
- 子表达式及运算符组合
- 函数调用:构造对应的‘环境’
- 模型:实际表现为eval和apply的相互作用
- p253 (define eval (exp env) (cond ((self-evaluating? exp) exp)
- ((variable? exp) (lookup-variable-value exp env))
- ((quoted? exp) (text-of-quotation exp))
- ...
- (define apply (procedure arguments) (cond
- ((primitive? procedure) (apply-primitive procedure arguments))
-
((compound? procedure) (eval-sequence
- (procedure-body procedure)
- (extend-environment (procedure-parameters procedure) arguments (procedure-environment procedure))))
- p255 list-of-values:总是从右向左(或相反)求值运算对象,无论基础的Lisp采用什么求值顺序?
- p259 这种用户定义变换称为宏,但引入了一个微妙的名字冲突问题 ...
- let*,命名let,。。。
- 运行求值器:setup-environment(恩,想起了v8里的runtime函数。。。)
- driver-loop:REPL
- 内部定义(对前面求值器实现局部变量的改进)
- 。。。为此只需在求值如何值表达式之前,在当前环境里建立起所有的局部变量
- lambda?
- p271 letrec:变量和约束都是同时建立的??这样也就允许了约束的递归
- p272 确实有可能不用letrec(甚至define)描述递归过程,但方式要微妙得多。。。
- 这里的例子是Y组合子吗?(lambda作用于lambda!)
- 将语法分析与执行分离(?中间代码?VM?):编译器
- eval:分为2个部分,analyze返回一个‘执行过程’(lambda对象)
- Scheme变形:惰性求值
- 正则序(Haskell)和应用序(Scheme)
- 严格与非严格:cons??
- 一个采用惰性求值的求值器:基本想法:延时参数不求值,转换为thunk对象
- 对thunk中表达式求值的过程:force
- 记忆第一次force的结果:按需调用;不记忆:按名调用
- 对thunk中表达式求值的过程:force
- p283 关于‘副作用’的复杂讨论:eval-sequence、for-each
- p284 ‘有了惰性求值后,流和表就完全一样了’
- Scheme变形2:非确定性计算(自动状态空间搜素?类似Prolog的声明式语言?)
- 或Python的list comprehension?
- (list (amb 1 2 3) (amb 'a 'b))
- p289 ‘深度优先搜索’or‘按照历史回溯’
- 脚注251:‘依赖导向的回溯’=>‘真值保持’
- 逻辑编程?
- 实现amb求值器:‘执行环境’和2个‘继续过程’(对应成功/失败分支,实现回溯的关键)
- p297 可能需要撤销(undo)副作用过程?
- p298 amb求值器中最复杂的问题,也就是那些将‘继续过程’在相互调用的执行过程之间传来传去的机制
- 逻辑程序设计
- p305 脚注262:合一算法和归结原理;Prolog的线性Horn子句
- e.g. Microshaft人事数据库(搞笑~):这有点像早期IBM的某个数据库;基于模式的查询系统
- p322 为数理逻辑提供过程性解释的问题:死循环~!
- not
- P(x) :- P(f(x))
- 寄存器机器里的计算
- 数据通路 & 控制器?
- GCD:remainder 不停地做减法?
- 子程序?continue寄存器:保存程序调用后的返回地址?
- 采用堆栈实现递归:save restore
- 控制器指令:(这已经是native compiler了吧?)
- 汇编程序
- extract-labels
- receive过程?
- update-insts!
- extract-labels
- p366 3.2.3 为指令生成执行过程?(再重新用Scheme实现控制器指令的解释执行???靠)-->‘模拟’
- assign
- test、branch、goto
- make-perform ?
- 监视机器执行(ring0/kernel debugger?)
- make-stack
- make-register
- 存储分配和GC(靠,这书是台湾人翻译的?)
- 存储看作向量:vector-ref vector-set!
- 无穷存储的假象:
- 例:(accumulate + 0 (filter odd? (enumerate-interval 0 n)))
- p379 ‘停止并复制’
- root寄存器:working和free区域;将所有root可达对象从working复制到free,然后交换working/free?
- 脚注300 另一种方法:‘mark-and-sweep’
- 显式控制的求值器
- 一个堆栈和7个寄存器:exp env val continue proc argl unev
- eval-dispatch
- apply-dispatch
- 尾递归
- 求值器的执行:eceval 3层模拟???
- 错误处理,signal-error
- 编译
- p398 脚注319:实际上,这种编译器可以比解释器做得更简单。。。
- (define (compile exp target linkage) ...
- p403 脚注321:反引号
- p411 脚注325:... 事实上,复杂的Lisp编译器也可以用堆栈保存实参而又不破坏尾递归 ...
- 指令序列的组合:append-instruction-sequences
- preserving
- tack-on-instruction-sequence
- p428 在一种新机器上实现Lisp:修改代码生成器(后端),为新机器生成代码;然后编译这个编译器本身!
- p430 代码生成器的C语言后端