找到并学习这门课的原因: 想要学习 functional programming
Week1 Introduction and Course-Wide Information
week1 很轻松, 主要介绍了这门课包含的内容, 课程目的和环境安装配置.
这门课被分为了三部分, Part A 使用ML语言, Part B 使用Racket语言, Part C 使用Ruby语言. 从Course Topics上来看, 这三部分的结构比较相似, 都是一开始介绍语言的基础, 然后涉及较高级的语法和编程思想. 三个部分对应于不同的编程思想, Part B, Part C 又会有跟之前介绍的编程思想的比较.
这个课程侧重于介绍 Functional Programming. Grossman 教授的原话是 The emphasis on functional programming is essential for learning how to write robust, reusable, composable, and elegant programs. Indeed, many of the most important ideas in modern languages have their roots in functional programming.
Course Goals 里面讲通过学习这门课程可以了解什么是 functional programming 什么是 object-oriented programming. 通过掌握基本的程序概念, 从而可以戳破一些语言的掩饰, 了解它的内在. 让你可以更快地学习新的语言...(好牛...好想学...)
这门课的作业评定方式是最终促使我一定要学的原因. 即使这个是一个在线课程, 作业并不是随意重复提交来刷分的. 你一天只有一次提交机会. 这就要求你必须自己经过认真的思考和足够的测试再选择提交. 还有就是这门课在我看来的精华部分Peer Review, 学生的作业会经过别人的review. 课程提供了样例代码和关于评分标准的描述. 而且, 每个学生都要Review三个同学的作业才算通过Peer Review环节. 我在写这部分整理的时候刚刚做完Week2的作业, Review了同学的四份作业, 即使很简单的问题, 有的同学也考虑得非常全面, 有的同学的代码要比样例代码写得更整洁和清晰. 从别人的代码中学习是我没有过的学习体验, 感觉打开的了新世界的大门.
课程要求的编辑程序是Emacs, SML, 使用在Emacs里直接输出结果的SML/NJ REPL功能.
PS: Emacs还真是蛮反人类的, 找到了批判Emacs的不便的文章.
一些肯定会用的Emacs快捷键
Shortcut | function |
---|---|
Ctrl + X , Ctrl + S | Save |
Alt + G , Alt + G , "N" (number) | Go to line N |
Ctrl + X , Ctrl + V | Read file from disk again |
Ctrl + X , O | Swtich foucus on windows |
Ctrl + X , 1 | Maximize the window |
Ctrl + X , Ctrl + B | Switch windows in list |
Alt
+ X
, "cua-mode"
开启cua-mode之后, 就可以使用 Ctrl + Z 撤销 Ctrl + C 复制, Ctrl + X 剪切, Ctrl + V 粘贴 后面的这些快捷键就不需要记了.
Shortcut | function |
---|---|
Ctrl + / | Undo |
Ctrl + space | Selection |
Ctrl + W | Cut Selction |
Alt + W / Ctrl + insert | Copy Selection |
Ctrl + Y | Paste |
Week2
这周的内容是:
- ML Basics
- ML 的基本表达式
- Variable Bindings, Variables are Immutable in ML
- Function
- Let 表达式
- ML 的比较运算符,逻辑运算符
- Pair, Tuple,List 这样的基本ML数据结构, 对这些数据结构的访问操作,操纵这些数据结构的递归函数
- 对ML的immutable data这样的特性的讨论。阐述immutable data的优点。* It is one of the main
contributions of functional programming.*
ML相比于c++, Java有太多不同点,所以学习的时候有种面对未知的强烈好奇心驱动。An ML program is a sequence of bindings. binding不能被修改, 习惯了可以修改变量的人可能会觉得变量不能修改是不是连程序都写不下去了。在ML中可以创建新的同名binding来shadow旧的binding,达到修改的同样目的。同时,旧的binding其实还存在在环境中。预感到这个特性应该是Functional Programming的基础。
这周的主要的Function都是基于对List操作。主要考虑对于长度未知的List的操作,这里的函数都是递归写成的。例如访问List直到访问到最后一个元素时终止,在逻辑上刚好和递归函数中的递归到达起始条件对应。所以写成递归函数看起来要比写while更自然简单。头一次连续写这么多递归函数,感受到了递归的美妙。
因为变量能被修改, 在写Java或者c++的时候把一个变量赋值之后为了防止被修改,在传递变量的时候要留心。引用传递,指针传递,值传递什么时候用或者加const是经常要考虑的。尽管如此还是会因为疏忽产生bug。但是,如果变量是不能被修改的,无论是引用传递还是值传递我们用起来都没什么区别,减少了很多考虑的负担和bug的来源。 所以Dan说 Having immutable data is probably the most important “non-feature" a language can have, and it is one of the main contributions of functional programming.
相当良心的是这门课除了提供Slides和Source Code之外,还提供Reading Notes里面就是本周涉及到的内容的整理,包含了这节课的大部分内容。我的英语听力不够好,这门课还有考试,所以听完课之后去戳了Reading Notes。因为听过课,读一遍的的速度很快,而且会发现一些没有在视频里了解的重要内容,对于巩固学习是很有效的。
我做完这周的作业,包含peer Review的部分,用了将近10小时的时间。作业本身并不难,所有涉及到的基本操作,在之前的课上和题目中都有给出。我花了不少的时间回去看Reading Notes和学着用Emacs。如果只是想拿到Auto Grader的100分还是可以很快的。这里重要的是从Sample中学习什么是好的style, Review别人的code看到别人写的好的地方。比如第12题的去重操作,有的同学考虑到了对List去重之后元素出现的次序是否被打乱的问题,所以写了两种:前向的不会打乱顺序的和后向的会打乱顺序的。(然后被我愉快地学(chao)习(xi)了233
(* To remove duplicates, and keep the order of appearence *)
fun remove_duplicates_forward (lst : int list) =
let
fun remove_element (target : int, lst_ : int list) =
if null lst_ then []
else if hd lst_ = target then remove_element(target, tl lst_)
else hd lst_ :: remove_element(target, tl lst_)
in
if null lst then []
else hd lst :: remove_duplicates_forward(remove_element(hd lst, lst))
end
(* To remove the duplicates, but not keep the order *)
fun remove_duplicates_backward (lst : int list) =
let
fun is_there (target : int, lst_ : int list) =
if null lst_ then false
else hd lst_ = target orelse is_there(target, tl lst_)
in
if null lst then []
else if is_there(hd lst, tl lst) then remove_duplicates_backward(tl lst)
else hd lst :: remove_duplicates_backward(tl lst)
end
作业代码在这里:homework1
Week3
来来来, 世界这么大. 上周介绍ML基础, 只有基本数据结构和特定的访问方式, 写程序仿佛在裹着脚走路. 这周直接打开了ML的大门, 仅仅是目光所及就让人眼花缭乱了.
这周主要讲的内容
- 如果我们不满足一个变量中只包含一个数据, 那么我们就需要定义复合型类型 compound type 可以分为三类
- each-of 方式, 可以类比下struct, 这个类型的变量其中包含各种类型的子元素.
- ML 中的 records (tuple实际上是它的语法糖) 就是each-of方式的~
- one-of 方式, 可以类比下C++中的union
- ML 中的 datatype
- self-reference 方式, 这种类型可以在定义中引用自己, 例如 ML 中的List~
- each-of 方式, 可以类比下struct, 这个类型的变量其中包含各种类型的子元素.
- 处理one-of类型数据 (i.e. datatype) 的case表达式
- 处理each-of类型数据的pattern matching. 非常强, Dan认为这部分是他在整个课程里最喜欢的部分
- 我们可以通过pattern matching和一个变量的操作来推断一个变量的类型, 意味着我们不需要写明变量类型了
- pattern matching如果嵌套在一起用会非常魔性!
- 教你使用尾递归! 因为ML编译器会对尾递归做编译器优化, 即尾递归会被优化为~1的空间占用. 这样子的话, ML的尾递归和OO语言的循环的效率是一样的.
学完这周完全被pattern matching和ML类型推断折服了, 写程序的时候摆脱变量类型定义的束缚的感觉真好. 当然心里是要有类型的.
体会到了语言设计的优美~ 之前学过, ML的程序是基于binding的, 学完这周我一共认识了ML中的四种binding. variable binding, function binding,datatype binding, exception binding
而list
实际上是一种datatype, list的constructor是NONE
和SOME
. exception
也是一种datatype, 当我们新声明一个exception, 实际上是给exception添加了一个constructor.
之前学过的tuple
实际上是records
的语法糖, 真正存在的只是records
.
表面上看到ML有很多基本组件, 然而实际上的核心的只有简单binding和基于binding的基本数据类型. 在这些基础上增加修饰, 封装(语法糖)就生成了我看到了拥有很多功能ML的语言. ML语言基本设置是易于它自己的发展和设计的. 同时也想到, 是不是可以认为这就是编程语言设计的哲学? 从而我们主要抓住一个语言最基础, 最核心的特征, 理解应用它的复杂属性就会变得容易多了. Dan设置这门课程的目的应该就是让我们能体会到这一点吧.
这周的内容比较多, 看视频, 看course notes, 做完作业有用了25+小时的时间, 不知道下周会不会更多. PS: 英语听力渣表示视频1.2倍速播放反而听力跟得上, 我也不知道为啥.
作业代码在这里:homework2