来源
sicp,计算机程序构造与解释,经典编程入门教材,以Lisp方言为教学语言。在csdiy中知道有这么一门课程——cs61a,使用python作为教学语言。在搜索中发现有一个up爱扑bug的熊, 整理并上传了英文资料中文授课的cs61a改(课程主页)。
重要链接:
2022.10.11 完成课程内容的一半
要点难点记录
虽然已经不是初学的菜鸟,但是这门课程的内容和配套的labs,homework和projects总能给我带来新的东西。做完递归,发现此前有很多东西可以记录一下,以供后续使用。
抽象 Absraction
没有什么问题是不能通过添加一层抽象解决的。
Name
第一个抽象
必须有具体的名字(name)才能被显示调用。
(匿名递归不需要暴露名字给外接,但是内部也需要一个具体的名字指称)
表达式计算顺序
操作符(operator) 和 操作数(operand) 都可能是 表达式,从左至右以此计算(evaluate)。
表达式可以嵌套,计算到基本表达式(Primitive Expressions)为止, 如数字,字符,函数
之后将操作符(operator) 应用到 操作数(operand(s)) 上
环境,特指frame
一个函数在哪儿被定义,哪儿的frame就是它的父环境。
一个frame的父环境是 被调用函数的父环境。
An environment is a sequence of frames. 环境就是一个帧序列
Name 查找从local frame开始,向父环境依次往上查找,选择最接近的一个。
高阶函数
将函数作为参数,将函数作为返回值的函数,是函数式编程的根基
重点在于demo和pythontutor的演示
自引用
1 | def print_sum(n): |
函数柯里化(currying)
将多个参数的函数转化为多个单参数函数
1 | 1,2,3) add( |
软工常识
TDD:先写测试,在写函数体
代码清晰易懂 > 代码短效率高
递归
函数签名需要考虑递归传递的信息;先定义 终止情形(base case);再定义 递归情况
递归的难点在于,寻找问题结构的相似之处 和 写代码时存在很多未知情况。
前者可以通过迭代解法找循环不变式发现,也可以通过对比大规模和小规模情况下的输出发现。
后者,我们可以抽象出一个函数,假设这个函数解决了这个部分的未知,使用这个函数继续描述问题解法,之后再完善抽象出的函数。
递归也可以多次调用自己,或者互相调用
几个经典问题:
汉诺塔、数字拆分
在homework2中,使用匿名函数完成递归
数据抽象
数据抽象:将数据的表示与数据的操作分隔开来。
有点像ADT(抽象数据类型),但是此时类型并未现身,仅仅是数据表示和操作。
关键点有两个, constructor 和selector (这两个词的中文翻译有点词不达意,直接用英文,之前做OS实验《一个操作系统的实现》导致对选择子过敏)
demo如下:
constructor 构造一个存储数据的结构(list,structure,hof都可以)
selector 将存储数据的结构中各个部分取出
上游和下游在不改变层际的接口时,互不影响。