scheme美观打印的格式规则,键值对
(+ (* 3
(+ (* 2 4)
(+ 3 5)))
(+ (- 10 7)
6))
Lisp的语法非常简单,对各种表达式的求值规则:
可以描述为一个简单的通用规则和一组针对不多的特殊形式的专门规则
过程定义的一般形式:
(define ( ) )
(define (square x) (* x x))
(define (abs x)
(cond ((> x 0) x)
((= x 0) 0)
((< x 0) (- x))))
**句法**
(cond ( )
( )
( )
)
(if )
** 最常用的三个符合运算符:**
能够构造复合数据对象的能力,可以处理与数据有关的各种问题
(make-rat )
(numer )
(denom
Lisp 表结构数据
数组的address的由来
过程 | 全称 | 解释 |
---|---|---|
cons | constrcut | 构造 |
car | contents of address part of register | 寄存器的地址部分的内容 |
cdr | contents of decrement part of register | 寄存器的减量部分的内容 |
闭包性质:
组合起数据对象得到的结果本身还可以通过同样的操作再进行组合。
人生第一个知道的拉丁词汇: nihil (虚无,毫无价值)
fringe:穗;非重要,次要的
使用约定的界面
在工程设计中,模块化结构式控制复杂度的一种威力强大的策略
展示数据抽象和闭包的威力
描述一种语言时,应该将注意力集中到语言的基本原语,它的组合手段以及它的抽象手段,这是最重要的。
wave: 挥手;舞动;波浪
roger: 已收到,明白;v,sex
vert: 绿色;森林中的草木;绿色的
在这一章里,我们要研究两种特点很鲜明的组织策略,它们源自对系统结构的两种非常不同的“世界观”。
第一种策略将注意力集中在对象上,将一个大型系统看成一大批对象,它们的行为可能随着时间的进展而不断变化。
另一种组织策略将注意力集中在流过系统的信息流上,非常像电子工程师观察一个信号处理系统。
即,基于对象的途径和基于流处理的途径。
局部状态变量
withdraw 取现金
insufficient funds金额不足
balance 平衡,均衡;账户余额
(+ 137 349)
(- 1000 334)
(* 5 99)
(/ 10 5)
(+ 2.7 10)
(+ 21 35 12 7)
(* 25 4 12)
(+ (* 3 5) (- 10 6))
(+ (* 3
(+ (* 2 4)
(+ 3 5)))
(+ (- 10 7)
6))
(define size 2)
size
(* 5 size)
(define pi 3.14159)
(define radius 10)
(* pi (* radius radius))
(define circumference (* 2 pi radius))
circumference
# out
486
666
495
2
12.7
75
1200
19
57
2
10
314.159
62.8318
circumference 周长
一个List程序通常总是由一大批相对简单的过程组成
(define (square x)
(* x x))
(square 21)
(square (+ 2 5))
(square (square 3))
(define (sum-of-squares x y)
(+ (square x) (square y)))
(sum-of-squares 3 4)
(define (f a)
(sum-of-squares (+ a 1) (* a 2)))
(f 5)
# out
441
49
81
25
136
条件表达式谓词
(define (ju x)
(and (> x 5) (< x 10)))
(ju 7)
10
(+ 5 3 4)
(- 9 1)
(/ 6 2)
(+ (* 2 4) (- 4 6))
(define a 3)
(define b (+ a 1))
(+ a b (* a b))
(= a b)
(if (and (> b a) (< b (* a b)))
b
a)
(cond ((= a 4) 6)
((= b 4) (+ 6 7 a))
(else 25))
(+ 2 (if (> b a) b a))
(* (cond ((> a b) a)
((< a b) b)
((else -1)))
(+ a 1))
# out
10
12
8
3
6
19
#f
4
16
6
(/ (+ 5 4 (- 2 (- 3 (+ 6 (/ 4 5)))))
(* (- 6 2) (- 2 7)))
-37/50
(set! )
(begin … )
表达式 到将按顺序求值,并且将最后一个表达式的值作为整个begin形式的值返回
scheme语法习惯里,赋值的操作都被以一个感叹号结尾;类似以问号结尾的名字表示谓词的习惯。
(define (make-account balance)
(define (withdraw amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance)
"Insufficient found"))
(define (deposit amount)
(set! balance (+ balance amount))
balance)
(define (dispatch m)
(cond ((eq? m 'withdraw) withdraw)
((eq? m 'deposit) deposit)
(else (error "Unknown request -- MAKE-ACCOUNT"
m))))
dispatch)
(define acc (make-account 100))
((acc 'withdraw) 50)
((acc 'withdraw) 60)
((acc 'deposit) 40)
((acc 'withdraw) 60)
计算机里的时间和现实世界的时间之间的关系??
3.2节 描述求值的环境模型??
元语言抽象就是建立新的语言。通过构造求值器可以实现这些语言。
求值器就是解释器:应用于这个语言的一个表达式时,它能够执行求值这个表达式所要求的工作。
组合手段和抽象手段
正则序求值??
4.4 节实现了逻辑程序设计语言??
元循环?? 用解释器的语言同样的语言写出来的解释器,称为元循环
求值器里两个关键过程:eval和applay的相互作用。??
一个新语言:
揭示计算机语言本质的eval-apply循环:
(make-procedure (
lookup-variable-value
apply-primitive-procudure
)
)
基本表达式
特殊形式
组合式
eval的定义
;; quotatoin引用,引文
(define (eval exp env)
(cond ((self-evaluating? exp) exp)
((variable? exp) (lookup-variable exp env))
((quoted? exp) (text-of-quotation exp))
((assignment? exp) (eval-assignment exp env))
((definition? exp) (eval-definition exp evn))
((if? exp) (eval-if exp env))
((lambda? exp)
(make-procedure (lambda-parameters exp)
(lambda-body exp)
env))
((begin? exp)
(eval-sequence (begin-actoins exp) env))
((cond? exp) (eval (cond->if exp) env))
((application? exp)
(apply (eval (operator exp) env)
(list-of-values (operands exp) env)))
(else
(error "Unknown expression type -- EVAL" exp))))
apply有两个参数,一个是过程,一个是该过程应该去应用的实际参数的表
(define (apply procudure arguments)
(cond ((primitive-procedure? procedure)
(apply-primitive-procedure procedure arguments))
((compound-procedure? procedure)
(eval-sequence
(procedure-body procedure)
(extend-environment
(procedure-parameters procedure)
arguments
(procedure-environment procedure))))
(else
(error
"Unknown procedure type -- APPLY" procedure))))
eval在处理过程应用时用list-of-values去生成实际参数表
;; 操作数;运算对象
(define (list-of-values exps env)
(if (no-operands? exps)
'()
(cons (eval (first-operand exps) env)
(list-of-values (rest-operands exps) env))))
eval-if在给定环境中求值if表达式的谓词部分,如果得到为真,结果为真
eval-if就去求值这个if的推论部分,否则它就求值替换部分
;; predicate谓语;使基于,断言
(if ()
() ;; if-predicate is true
() ;; if-predicate is false
)
;; consequent 由此发生;后件,推断
;; alternative备选的
(define (eval-if exp env)
(if (true? (eval (if-predicate exp) env))
(eval (if-consequent exp) env)
(eval (if-alternative exp) env)))
eval-sequence用在apply里,用于求值过程体里的表达式序列,它也用在eval里
用于求值begin表达式里的表达式序列,这个过程以一个表达式序列和一个环境为参数,按照
序列列表里的表达式出现的顺序对它们求值,它返回最后一个表达式的值
(define (eval-sequence exps env)
(cond ((last-exp? exps) (eval (first-exp exps) env))
(else (eval (first-exp exps) env)
(eval-sequence (rest-exps exps) env))))
下面的过程处理变量赋值,它调用eval找出需要赋的值,将变量和得到的值传给过程set-variable-value!,将有关的值安置到指定环境里
(define (eval-assignment exp env)
(set-variable-value! (assignment-variable exp)
(eval (assignment-value exp) env)
env)
'ok)
(define (eval-definition exp env)
(define-variable! (definition-variable exp)
(eval (definition-value exp) env)
env)
'ok)
(define (self-evaluating? exp)
(cond ((number? exp) true)
((string? exp) true)
(else false)))
(define (variable? exp)
(symbol? exp))
(define (quoted? exp)
(tagged-list? exp 'quote))
(deifne (text-of-quotation exp)
(cadr exp))
(define (tagged-list? exp tag)
(if (pair? exp)
(eq? (car exp) tag)
false))
(define (assignment? exp)
(tagged-list? exp 'set!))
(define (assignment-variable exp) (cadr exp))
(define (assignment-value exp) (caddr exp))
(define
(lambda ( ... )
))
;; tagged标记的
(define (definition? exp)
(tagged-list? exp 'define))
(define (definition-variable exp)
(if (symbol? (cadr exp))
(cadr exp)
(caadr exp)))
(define (difinition-value exp)
(if (symbol? (cadr exp))
(caddr exp)
(make-lambda (cdadr exp) ; formal parameters
(cddr exp)))) ; body
lambda表达式是由符号lambda开始的表
(define (lambda? exp) (tagged-list? exp 'lambda))
(define (lambda-parameters exp) (cadr exp))
(define (labmda-body exp) (cddr exp))
lambda表达式提供了一个构造函数
(define (make-lambda parameters body)
(cons 'lambda (cons parameters body)))
条件式由if开始,有一个谓词部分predicate,一个推论部分consequent,一个可缺省的替换部分alternative
(define (if? exp) (tagged-list? exp 'if))
(define (if-predicate exp) (cadr exp))
(define (if-consequent exp) (caddr exp))
(define (if-alternative exp)
(if (not (null? (cdddr exp)))
(cadddr exp)
'false))
为if表达式提供一个构造函数,它在cond-if中使用
(define (make-if predicate consequent alternative)
(list 'if predicate consequent alternative))
begin包装起要给表达式序列
(define (begin? exp) (tagged-list? exp 'begin))
(define (begin-actions exp) (cdr exp))
(define (last-exp? seq) (null? (cdr seq)))
(define (first-exp seq) (car seq))
(define (rest-exps seq) (cdr seq))
构造函数sequence->exp,它把一个序列变换为一个表达式,如果需要的话就加上begin作为开头
(define (sequence->exp seq)
(cond ((null? seq) seq)
((last-exp? seq) (first-exp seq))
(else (make-begin seq))))
(define (make-begin seq) (cons 'begin seq))
(define (application? exp) (pair? exp))
(define (operator exp) (car exp))
(define (operands exp) (cdr exp))
(define (no-operands? ops) (null? ops))
(define (first-operand ops) (car ops))
(define (rest-operands ops) (cdr ops))
派生表达式
一些特殊形式的可以基于其他特殊形式的表达式定义出来,而不必直接去实现。
(cond ((> x 0) x)
((= x 0) (display 'zero) 0)
(else (- x)))
;; 可以规约为下面涉及if和begin的表达式的求值问题
(if (> x 0)
x
(if (= x 0)
(begin (display 'zero)
0)
(- x)))
;; 这里包含了提取cond表达式中各个部分的语法过程,以及过程cond->if
(define (cond? exp) (tagged-list? exp 'cond))
;; clause 子句
(define (cond-clauses exp) (cdr exp))
(define (cond-else-calause? clause)
(eq? (cond-predicate clause) 'else))
(define (cond-predicate clause) (car clause))
(define (cond-actions clause) (cdr clause))
(define (cond->if exp)
(expand-clauses (cond-clauses exp)))
(define (expand-clauses clauses)
(if (null? clauses)
'false ; clause else no
(let ((first (car clauses))
(rest (cdr clauses)))
(if (cond-else-clause? first)
(if (null? rest)
(sequence->exp (cond-actions first))
(error "ELSE clause isn't last -- COND->IF"
clauses))
(make-if (cond-predicate first)
(sequence->exp (cond-actions first))
(expand->clauses rest))))))
let表达式也被作为派生表达式,见练习 4.6
let*与let类似,但其中对let变量的约束时从左到右顺序进行的
(let* ((x 3)
(y (+ x 2))
(z (+ x y 5)))
(* x z))
许多语言都支持多种迭代结构,例如:do, for, while 和util
在scheme里,迭代计算过程可以通过常规过程调用的方式表述
请为scheme设计和实现一种新的语法形式,通过数据抽象技术??
除了需要定义表达式的外部语法形式之外,求值器的实现还必须定义好在其内部实际操作的数据结构
,作为程序执行的一部分,例如,定义好过程和环境的表示形式,真和假的表示形式等等
除了false对象之外的所有东西都是接受为真
(define (true? x)
(not (eq? x false)))
(define (false? x)
(eq? x false))
处理基本过程
(apply-primitive-procedure )
它能够给定的过程应用于表里的参数值,并返回这一应用的结果
(primitive-procedure? )
检查是否为一个基本过程
处理基本过程的机制在 4.1.4节中详细讨论??
(define (make-procedure parameters body env)
(list 'procedure parameters body env))
;; compound 混合物,混合
(define (compound-procedure? p)
(tagged-list? p 'procedure))
(define (procedure-parameters p) (cadr p))
(define (procedure-body p) (caddr p))
(define (procedure-environment p) (cadddr p))
求值器需要对环境的一些操作
一个环境就是一个框架的序列,每个框架都是一个约束的表格, 其中的约束关联起一些变量和与之对应的值
(lookup-variable-value )
返回符号在环境里的约束值,如果这一变量没有约束就发出一个错误信号
(extend-environment )
返回一个新环境,这个环境中包含了一个新的框架,其中的所有位于表里的符号约束到表里对应的元素,而其外围环境是环境
(define-variable! )
在环境的第一个框架里加入一个新的约束,它关联起变量和值
(set-variable-value! )
修改变量在环境里的约束,使得该变量现在约束到值,如果这一变量没有约束就发出一个错误信号
;; enclosing封闭,围合
(define (enclosing-environment env) (cdr env))
(define (first-frame env) (car env))
(define the-empty-environment '())
(define (make-frame variables values)
(cons variables values))
(define (frame-variables frame) (car frame))
(define (frame-values frame) (cdr frame))
(define (add-binding-to-frame! var val frame)
(set-car! frame (cons var (car frame)))
(set-cdr! frame (cons val (cdr frame))))
(define (extend-environment vars vals base-env)
(if (= (length vars) (length vals))
(cons (make-frame vars vals) base-env)
(if (< (length vars) (length vals))
(error "Too many arguments supplied" vars vals)
(error "Too few arguments supplied" vars vals))))
要么在一个环境中查找一个变量,就需要扫描第一个框架里的变量表。如果找到了所需的变量,就返回与之对应的值表里的对应元素
如果在当前框架里找不到这个变量,就到其外围环境里去查找,并如此继续下去,如果遇到空环境,那么就发出一个“未约束变量”的错误
(define (lookup-variable-value var env)
(define (env-loop env)
(define (scan vars vals)
(cond ((null? vars)
(env-loop (enclosing-environment env)))
((eq? var (car vars))
(car vals))
(else (scan (cdr vars) (cdr vals)))))
(if (eq? env the-empty-environment)
(error "Unbound variable" var)
(let ((frame (first-frame env)))
(scan (frame-variable frame)
(frame-values frame)))))
(env-loop env))
在需要为某个变量在给定环境里设置一个新值时,我们也要扫描这个变量,就像在过程loopup-variable-value里一样,在找到这一变量后修改它的值
(define (set-variable-value! var val env)
(define (env-loop env)
(define (scan vars vals)
(cond ((null? vars)
(env-loop (enclosing-environment env)))
((eq? var (car vars))
(set-car! vals val))
(else (scan (cdr vars) (cdr vals)))))
(if (eq? env the-empty-environment)
(error "Unbound variable -- SET!" var)
(let ((frame (first-frame env)))
(scan (frame-variable frame)
(frame-values frame)))))
(env-loop env))
为了定义一个变量,需要在第一个框架里查找该变量的约束,如果找到就修改其约束,如果不存在这种约束,就在第一个框架中添加这种约束
(define (define-variable! var val env)
(let ((frame (first-frame env)))
(define (scan vars vals)
(cond ((null? vars)
(add-binding-to-frame! var val frame))
((eq? var (car vars))
(set-car! vals val))
(else (scan (cdr vars) (cdr vals)))))
(scan (frame-variables frame)
(frame-values frame))))
认知掌握一个东西的方式
重复熟悉的次数达到了解其细节的方方面面
将求值器描述为一个程序的一个优点是我们可以运行这个程序,这样就给了我们一个能够在Lisp里运行的,有关Lisp本身
如何完成表达式求值的工作模型,这一模型可以作为一个工作框架,使人能够去试验各种求值规则。
运气求值器
;; 如果这都还不足以明白程序的运行机制,那就没谁了
(define the-global-environment (setup-environment))
(driver-loop)
;; M-Eval input:
(define (append x y)
(if (null? x)
y
(cons (car x)
(append (cdr x) y))))
;;; m-Eval value:
ok
;;; M-Eval input:
(append '(a b c) '(d e f))
;; M-Eval value:
(a b c d e f)
基于传统计算机的一步一步操作,描述一些计算过程,这类计算机叫寄存器机器。
他们能顺序地执行一些指令,对一组固定称为寄存器的寄存器单元的内容完成各种操作。
寄存器设计包括设计它的数据通路(寄存器和操作)和控制器,控制器实现操作的顺序执行。
(define (gcd a b)
(if (= b 0)
a
(gcd b (remainder a b))))
(controller
test-b
(test (op =) (reg b) (const 0))
(branch (label gcd-done))
(assign t (op rem) (reg a) (reg b))
(assign a (reg b))
(assign b (reg t))
(goto (label test-b))
gcd-done)
;;
(data-paths
(registers
((name a)
(buttons ((name a<-b) (source (register b)))))
((name b)
(buttons ((name b<-t) (source (register t)))))
((name t)
(buttons ((name t<-r) (source (operation rem))))))
(operations
((name rem)
(inputs (register a) (register b)))
((name =)
(inputs (register b) (constant 0))))
(controller
test-b
(test =)
(branch (label gcd-done))
(t<-r)
(a<-b)
(b<-t)
(goto (label test-b))
gcd-done)
子曰:学而时习之,不亦悦乎
人的思维方式和行为习惯是具有连续性,物理上说有习惯性,该连续性的力量非常大,也即习惯的力量。
下一个小时或未来在处理的事情跟上一个小时和前一段时间所处理的事情一致或大概内容相同的概率非常大,人生中很多时候我们
都是同一时间段基本处理或面对相同的问题,所以结论是,想要提高下一个小时或未来做某件事的概率,就需要在上一个小时或上一段时间开始做某件事。
论据:
显式控制求值器
编译器编译任何Lisp程序是什么意思???
去编译编译器本身是什么意思???然后在新的机器上运行这一编译结果???去编译其他的Lisp程序???
去编译4.1节里的一个解释器,生成一个可以在新机器上运行的解释器???
求值器所用的堆栈操作??
计算所用的编译后代码所用的堆栈操作??
阶乘计算n!时,求值器所需的压栈次数和最大堆栈深度??
手工打造的控制器代码??
程序员可以控制在编译代码中错误检查的范围和种类??
C和C++的编译器通常都不将错误检查代码加入到运行代码里,以便使程序尽可能快速。这样的结果,实际将显示提供错误检查的问题交给程序员处理??
无论编译策略还是解释策略,都需要为新机器实现存储分配,输入输出,及求值器和编译器作出的基本操作。也可在Lisp程序中写出他们,然后新机器中编译它们??
内核其实很小,就是废料收集和实际的基本机器操作??
请在C/C++里开发一个初步的scheme实现,采用的方法是5.4节的显式控制求值器翻译到C/C++,为运行这一例程,需要提供适当的存储分配例程和其他运行支持??
编译4.1节的元循环求值器,生成一个用C写出的scheme解释器??
将编译得到的代码装入求值器??
compile-and-go,它能编译一个scheme表达式,将目标代码装入这部求值器机器,并启动该机器??
(compile-and-go )
盖茨是将别人把basic语言移植到windows平台上的语言继续开发
总部的业务:
业务单子:
模拟测试
内网ip一直不对,知道把子网掩码从255.255.0.0改成255.255.255.0就可以了,为什么??
求值过程中,最重要的就是一个过程调用其他过程以及将值返回调用者的机制的细节,通过简单的寄存器观察这一求值过程??