1.1 Recursively Specified Data
1.1.1 Inductive Specification
归纳定义法,定义数据结构,有以下几种定义方式:
- top-down(从终点进行回溯,直到原点)
- bottom-up(类似数学归纳法,从原点出发)
- rules-of-inference(bottom-up的形式化表示)
1.1.2 Defining Sets Using Grammars
1.1.1小节定义的递归数据结构很直观,但是描述复杂结构式会显的很笨重,不够形式化和通用性,因此这节引入grammars来定义递归数据结构。还有一个原因是这种定义方法更适合转化成Scheme程序。
grammar定义法构成要素:
- Nonterminal Symbols(所定义的数据结构名称)
- Terminal Symbols(分割符,具有特殊意义)
- Productions(包括左右两个部分,左边是定义的数据结构名称,右边是构造这类数据结构的方式)
例如lambda calculus数据结构的表示:
LcExp ::= Identifier | (lambda (Identifier) LcExp) | (LcExp LcExp)
不过此种定义法是context-free(不依赖上下文)的,因此无法定义一个二叉搜索树。程序语言的语法是context-sensitive(依赖于上下文)的,比如变量的使用只能在变量定义之后,使用依赖于上下文。
1.1.3 Induction
归纳定义法可以用来证明理论,也可以用来编写程序操纵该数据结构。
Proof by Structural Induction
To prove that a proposition IH(s) is true for all structures s, prove the following:
- IH is true on simple structures (those without substructures).
- If IH is true on the substructures of s, then it is true on s itself.
1.2 Deriving Recursive Programs
The Smaller-Subproblem Principle
If we can reduce a problem to a smaller subproblem, we can call the procedure that solves the problem to solve the subproblem.
1.2.1 list-length
1.2.2 nth-element
1.2.3 remove-first
1.2.4 occurs-free?
1.2.5 subst
** Follow the Grammar!**
When defining a procedure that operates on inductively defined data, the structure of the program should be patterned after the structure of the data.
1.3 Auxiliary Procedures and Context Arguments
No Mysterious Auxiliaries!
When defining an auxiliary procedure, always specify what it does on all arguments, not just the initial values.
1.4 Exercises
;; 1.34
(define path
(lambda (n bst)
(cond
((null? bst) #f)
((< n (car bst))
(let ([path1 (path n (cadr bst))])
(if path1
(cons 'left path1)
'())))
((> n (car bst))
(let ([path1 (path n (caddr bst))])
(if path1
(cons 'right path1)
'())))
(else '()))))