Sicp简单了解
基本语法:
(+ 3 8) (* 3 (+ 7 19.5)) (+ (+ 5 4) (* 6 (- 9 4))) 复制代码
- 3 + 8 的和
- 3 * (7 + 19.5)
定义:
组织函数:
最简单的组织一个定义方式
(define (square x) (* x x)) 复制代码
使用lambda表达式
(define square (lambda (x) (* x x)) ) 复制代码
定义的组织函数本身也可以作为内容的一部分
(define (sq x) (* x x)) (define (sum x y) (* (sq x) (sq y))) 复制代码
这样设计的好处:
- 可以让程序员灵活的搭配组织简单的程序形成复杂的程序
- 没有语言的约束,只有基本的语法规则
坏处:
- 你无法知道哪些是定义,哪些是引用
- 程序的可读性较差
条件语句:
cond:可以理解为switch ( (p1 p2) (p3 p4) (p5 p6) )
如果没有唯一的一个cond 的值,则cond 会没有定义
cond (<p1> <e1>) (<p2> <e2>) ....... (<pn> <en>)) 或者 (cond (<p1> <e1>) (<p2> <e2>) ....... (else <en>)) 复制代码
应用:
(define (sq3 y) ((cond ((> y 0) y) ((= y 0) 0) ((< y 0) (- y))))) 复制代码
另一种写法:
(define (sq5 k) (cond ((< k 0) (- k)) (else k))) 复制代码
if:是一种语法糖:
(define (zz x) (if (> x 0) (-1) x)) 复制代码
- 把自己的作为结果,带入到函数当中求值返回
(and ..... )
(define (test t) (and (> t 5) (< t 1))) 复制代码
(or ..... )
(define (test t) (or (> t 5) (< t 1))) 复制代码
(not ..... )
(define (test t) (not (> t 5) (< t 1))) 复制代码
什么是正则序求值,什么是应用序求值
结论:Lisp使用的是应用序求值
正则序求值:使用过程组合,层层的代换展开运算,最后完全展开运算完成的这个过程就叫做正则序求值(可以理解为懒加载,在只有实际使用到参数的时候,才会带入参数运算)
应用序求值:应用序求值,先对每一个形式参数带入实际的值进行实际的运算操作,直到返回最终结果
为什么Lisp使用应用序求值?
- 减少没有必要的计算,比如说正则序列求值,需要将一步完成的计算继续拆分为更多步骤
- 正则的结果不一定完全正确(特殊案例)
课后练习:
网络异常,图片无法展示
|
非常好的一个问题:
在定义的时候,如下面所示的括号有无的区别
(define (d) (* 5 5)) (define d (* 5 5)) > 输入 a = 5 结果 25 > 输入 d = 5 结果 25 两者内部的细节区别: (define (d) (* 5 5)) -> 运行的是一个复合公式 (define d (* 5 5)) -> 函数的结果 复制代码
课后练习 1.2
(/ (+ 5 4 (-2 (-3 (+ 6 (/ 4 5))))) (* 3 (- 6 2) (- 2 7))) 复制代码
解决思路:其实挺简单的,画树就行
课后练习 1.3
题目:求较大两数的两树之和?
分析:
使用双层if判断
拆分
(define (maxVal3 x y z) (if (> x y) (if (> y z) (* x y) (* x z)) (* z y))) 复制代码
课后练习 1.4
(define (a-plus-abs-b a b) ((if (> b 0) + -) a b)) 复制代码
- if (b > 0)
- + a b
- if(b < 0)
- - a b
解答:
可知,由于(define (p) (p)), 如果出现了对(p)求值的情况, 就会陷入循环 scheme中的解释器本身就是应用序的,函数的求值会先对每一个参数进行求值, 然后把参数的值代入函数,若对(test 0 (p))使用应用序,那么(p)就会被求值, 进入死循环中。而正则序是“完全展开而后规约”,在展开之后,由if条件判断,然后 对0求值,由于(p)不会进行求值,最终函数可以正确返回0值。 (Guile中测试此程序确会进入死循环。)
PS:这一段网上摘录的答案还不是很了解,还没有进行实际的验证