【Scheme】计算机程序的构造和解释-笔记(1)
# 前言## 为什么要学计算机程序的构造与解释
http://blog.zhaojie.me/2009/07/recommended-reading-2-sicp.html很老的一个帖子上的推荐
+ 了解任何东西,思想最重要
+ 抽象的思维,如何从简单到复杂
+ 用不同的角度去考虑用咒语来实现功能
+ 学习任何语言思想最重要的是思想本身,而scheme由于语言天生的自由性,可以极大的发挥程序员的思想空间
+ 学习思考问题的方式,以及解题思路
https://www.jianshu.com/p/0e6365f4bb03?utm_campaign=shakespeare 简书上面做的一个回答
## 一些感谢:
1. 文科生学这个表表示虽然痛苦,但是会努力一步一步的学习
2. 写出来是监督自己产出,这门语言非常深奥和困难,借助视频和书籍慢慢啃
3. 一定要深入的理解黑盒抽象的思维,解题的思路大于题目本身的意义
4. 持续更新,用文章输出来勉励和督促自己。
# 第一节课 上课笔记
## 计算机科学
1. y^2 = x && y>= 0
2. 亚历山大的连续平方根
3. 知道规则不等于可以运用规则
4. 复杂度控制
1. 黑盒抽象
2. 猜测->验证结果
5. 寻找函数的不动点
1. 输入
2. 输出
6. 线性组合的基本方法
7. 构建大型程序
1. 流
2. OOP
## 黑盒抽象
![](https://gitee.com/lazyTimes/imageReposity/raw/master/img/20200926145204.png)
## 元语言抽象
1. 数据抽象:如何组合程序的基本元素,构造更复杂的结构
2. 过程抽象:如何将复杂的结构抽象出高层组件,提供更高维度的组合型
3. 模块化,通过高抽象层次的组织方法,提高系统的模块性
## 约定接口
1. 对应计算机的输入与输出
2. 使用黑盒不需要知道内部结构,只需要知道约定俗称的接口的功能
## 在进行正式SCIP学习之前,需要安装环境
### 1. 下载 DrRacket
直接访问:https://racket-lang.org/
找到自己对应的内容下载页面
![](https://gitee.com/lazyTimes/imageReposity/raw/master/img/20200926152047.png)
### 2. 安装
下载完安装包之后,就可以进行安装操作了
![](https://gitee.com/lazyTimes/imageReposity/raw/master/img/20200926154022.png)
注意不要安装在C盘,一般习惯是直接切换一个盘符,直接安装到D盘即可
安装好之后,你在桌面上可能找不到你要的东西,所以请查看一下你的开始菜单(MAC不了解,这里只能说明windows的地址,抱歉)
![](https://gitee.com/lazyTimes/imageReposity/raw/master/img/20200926154221.png)
### 3. DrRacket
这个界面怎么说呢,如果你用过C语言的编辑器(没错就是老掉牙的那个),其实感觉还行,但是如果经常使用中文的菜单可能不习惯
![](https://gitee.com/lazyTimes/imageReposity/raw/master/img/20200926154557.png)
没关系,在HELP里面,可以切换:
![](https://gitee.com/lazyTimes/imageReposity/raw/master/img/20200926154650.png)
### 4. 安装 SICP Package
1. 选择`File` -> `Package Manger`
![](https://gitee.com/lazyTimes/imageReposity/raw/master/img/20200926154758.png)
2. 在标红的地方,输入`sicp`
![](https://gitee.com/lazyTimes/imageReposity/raw/master/img/20200929214408.png)
3. 下载比较建议挂个梯子下载,需要访问github进行安装包的下载
![](https://gitee.com/lazyTimes/imageReposity/raw/master/img/20200926155047.png)
4. 安装成功之后,大概类似这种界面
![](https://gitee.com/lazyTimes/imageReposity/raw/master/img/20200926155154.png)
### 5. 测试 SICP package 安装成功与否
1. 首先在顶部输入`#lang sicp`然后`run`一下,如果看到下面的语言切换了,说明成功了。
![](https://gitee.com/lazyTimes/imageReposity/raw/master/img/20200926155408.png)
2. 接着输入如下的方法:
```basic
#lang sicp
(define (increase x) (+ x 1))
```
![](https://gitee.com/lazyTimes/imageReposity/raw/master/img/20200926155727.png)
6. 文件夹管理的包:`files-viewer`,类似插件,安装方式如下:
![](https://gitee.com/lazyTimes/imageReposity/raw/master/img/20200926160110.png)
## Sicp简单了解
### 基本语法:
```scheme
(+ 38)
(* 3 (+ 7 19.5))
(+ (+ 5 4) (* 6 (- 9 4)))
```
1. 3 + 8 的和
2. 3 * (7 + 19.5)
#### 定义:
组织函数:
最简单的组织一个定义方式
```scheme
(define (square x) (* x x))
```
使用lambda表达式
```scheme
(define square (lambda (x) (* x x)) )
```
定义的组织函数本身也可以作为内容的一部分
```scheme
(define (sq x) (* x x))
(define (sum x y) (* (sq x) (sq y)))
```
这样设计的好处:
1. 可以让程序员灵活的搭配组织简单的程序形成复杂的程序
2. 没有语言的约束,只有基本的语法规则
坏处:
1. 你无法知道哪些是定义,哪些是引用
2. 程序的可读性较差
#### 条件语句:
##### cond:可以理解为switch ( (p1 p2) (p3 p4) (p5 p6) )
如果没有唯一的一个cond 的值,则cond 会没有定义
```
cond (<p1> <e1>)
(<p2> <e2>)
.......
(<pn> <en>))
或者
(cond (<p1> <e1>)
(<p2> <e2>)
.......
(else <en>))
```
应用:
```scheme
(define (sq3 y)
((cond ((> y 0) y)
((= y 0) 0)
((< y 0) (- y)))))
```
另一种写法:
```scheme
(define (sq5 k)
(cond ((< k 0) (- k))
(else k)))
```
##### if:是一种语法糖:
```scheme
(define (zz x)
(if (> x 0)
(-1)
x))
```
1. 把自己的作为结果,带入到函数当中求值返回
##### (and <e1> ..... <e2>)
```scheme
(define (test t)
(and(> t 5) (< t 1)))
```
##### (or<e1> ..... <e2>)
```scheme
(define (test t)
(or (> t 5) (< t 1)))
```
##### (not<e1> ..... <e2>)
```scheme
(define (test t)
(not (> t 5) (< t 1)))
```
### 什么是正则序求值,什么是应用序求值
结论:Lisp使用的是应用序求值
正则序求值:使用过程组合,层层的代换展开运算,最后完全展开运算完成的这个过程就叫做正则序求值(可以理解为懒加载,在只有实际使用到参数的时候,才会带入参数运算)
应用序求值:应用序求值,先对每一个形式参数带入实际的值进行实际的运算操作,直到返回最终结果
为什么Lisp使用应用序求值?
1. 减少没有必要的计算,比如说正则序列求值,需要将一步完成的计算继续拆分为更多步骤
2. 正则的结果不一定完全正确(特殊案例)
### 课后练习:
![](https://gitee.com/lazyTimes/imageReposity/raw/master/img/20200926164058.png)
### 非常好的一个问题:
在定义的时候,如下面所示的括号有无的区别
```basic
(define (d) (* 5 5))
(define d (* 5 5))
> 输入 a = 5
结果 25
> 输入 d = 5
结果 25
两者内部的细节区别:
(define (d) (* 5 5)) -> 运行的是一个复合公式
(define d (* 5 5))-> 函数的结果
```
### 课后练习 1.2
```scheme
(/ (+ 5 4 (-2 (-3 (+ 6 (/ 4 5))))) (* 3 (- 6 2) (- 2 7)))
```
解决思路:其实挺简单的,画树就行
### 课后练习 1.3
题目:求较大两数的两树之和?
分析:
使用双层if判断
拆分
```scheme
(define (maxVal3 x y z)
(if (> x y)
(if (> y z) (* x y)
(* x z))
(* z y)))
```
### 课后练习 1.4
```scheme
(define (a-plus-abs-b a b) ((if (> b 0) + -) a b))
```
1. if (b > 0)
1. \+ a b
2. if(b < 0)
1. \- a b
### 解答:
> **可知,由于(define (p) (p)), 如果出现了对(p)求值的情况, 就会陷入循环
>scheme中的解释器本身就是应用序的,函数的求值会先对每一个参数进行求值,
> 然后把参数的值代入函数,若对(test 0 (p))使用应用序,那么(p)就会被求值,
> 进入死循环中。而正则序是“完全展开而后规约”,在展开之后,由if条件判断,然后
> 对0求值,由于(p)不会进行求值,最终函数可以正确返回0值。
>(Guile中测试此程序确会进入死循环。)**
>
> PS:这一段网上摘录的答案还不是很了解,还没有进行实际的验证 谢谢分享了! hu007 发表于 2020-10-7 11:39
谢谢分享了!
感谢支持
页:
[1]