对于了解所有的语言,首先要了解
- Primitive elements 基本元素
- Means of combination 如何把这些基本元素组合在一起,组合在一起之后的含义是什么,构建出来更大的对象是什么
- Means of abstraction 如何利用基本元素进行封装,如何做使得它们可以像基本元素一样使用,以逐渐构建复杂的东西
Primitive elements & Means of combination
Combination 组合式 格式: (+ 3 17.4 5)
- operator 运算符
- operands 运算对象
Lisp 的括号不同于数学的括号
- 数学中的括号用于分组,有些时候可以省略,多加也只会使得分组更明确
- Lisp 的括号总是意味着所括之物是另一个组合式,在 apply operators to operands,不能多了也不能少了
❌ (* (5) A)
SchemeError: Cannot call 5
Current Eval Stack:
-------------------------
0: (5)
1: (* (5) A)
❌ * (5) A
PrimitiveProcedure
SchemeError: Cannot call 5
Current Eval Stack:
-------------------------
0: (5)
SchemeError: unknown identifier: A
Current Eval Stack:
-------------------------
0: A
1: (5)
Lisp 的 combination 实际上是一棵将二维结构写作线性字符串的语法树
在线运行 Lisp 地址:https://inst.eecs.berkeley.edu/~cs61a/fa14/assets/interpreter/scheme.html
3
(+ (* 3 5)
(* 47
(- 20 6.8))
12)
3
647.4
Means of abstraction
抽象化一些组合式并给它命名,使得可以将其作为一个元素
不带参数的组合式:
(define A(+ 5 5))
(* A A)
(define B(+ A(* 5 A)))
带参数的组合式:
(define (SQUARE X)(* X X))
用 lambda 方式命名带参数的组合式,对 lisp 来说和上面的没区别,只是 syntactic sugar:
(define SQUARE
(lambda (X) (* X X)))
define 后面有的时候加括号,有的时候不加
define SQUARE 代表定义的是一个符号 SQUARE,把这个符号定义为一个 lambdadefine (SQUARE X) 是定义一个 procedure,这个 procedure 带一个参数是 X
如果 define (A)(* 5 5) 也是可以的,这就是定义一个没有参数的 procedure A
具体的:(define (A) (* 5 5)) A (A) A -> (lambda () (* 5 5)) (A) -> 25 (define A (* 5 5)) A (A) A -> 25 SchemeError: Cannot call 25 Current Eval Stack: ------------------------- 0: (A)
带参数过程的使用:
(SQUARE 1001)
(+ (SQUARE 3) (SQUARE 4))
(SQUARE (SQUARE (SQUARE 1001)))
我们无法分辨内建元素(things are built in)与复合元素(things are compound)的区别,因为复合元素经过了一层抽象封装(abstraction wrapper)
Conditional 的过程:
(define (ABS X)
(cond ((< X 0)(-X)))
(< X 0) 是谓词 predicate / 条件 condition,return true or false
上述式子等价于
(define (abs x)
(if (< x 0)
(- x)
x))
用以上学的内容写平方根(f(y)=x/y 的不动点)
double sqrt(double x){
double guess=1;
while(abs(guess - x/guess)>=0){
guess=(guess + x/guess)/2;
}
return guess;
}
可以看到似乎需要 while,这个上面没有
所以我们用递归来代替
(define (improve guess x)
(average guess(/ x guess)))
(define (good-enough? guess x) // good-enough? 整体是一个名称
(< (abs (- (square guess) x))
.001))
(define (try guess x)
(if (good-enough? guess x) // 如果足够好
guess // 进这里 return guess
(try (improve guess x) x))) // 否则进这里
(define (sqrt x)(try 1 x))
(sqrt 2)
可以将 improve,good-enough?和 try 放进 sqrt 中
进行了封装,省去了多余的 x 传递
block-structure
(define (sqrt x)
(define (improve guess)
(average guess(/ x guess)))
(define (good-enough? guess) // good-enough? 整体是一个名称
(< (abs (- (square guess) x))
.001))
(define (try guess)
(if (good-enough? guess) // 如果足够好
guess // 进这里 return guess
(try (improve guess)))) // 否则进这里
(try 1))
(sqrt 2)