Coursera

CSE341: Programming Languages

感谢华盛顿大学 Dan Grossman 老师 以及 Coursera

碎言碎语

  • 这只是 Programming Languages 这门课程第一部分,在 Part A 中通过 Standard ML 这门编程语言把函数式编程的美妙娓娓道来。在 Part B 以及 Part C 中分别会学习 Racket 以及 Ruby 。

  • 这是一门什么样的课呢?首先,它很好玩,虽然我学过 Scala 学过一些 Scheme,但还是能够感觉到这门语言的简洁和优雅。但是要记住,这门课最重要的不是教你学会 Standard ML 这门语言,而是函数式编程中的 immutable data 、function closures 、first-class function、higher-order function,以及这门语言中的 pattern matching、currying and partial application、type inference 等等(当然并不是这门语言所特有的,这些特性在 Scala 中都存在)。不仅仅是这些实际的东西,在 Part A 的 week 4 最后有几乎一小时的视频介绍了这门课程的动机:为什么要学习函数式编程?为什么选择这三门语言?

  • 为什么我会去学习这门课呢?首先这是华盛顿大学的一门 CS 课程,在网络上的评价很高,它的课程质量和作业质量得到了保证。再看看这门课程,它一共使用了三门编程语言,既有函数式编程也有面向对象编程,它并不会试图告诉你这门语言的全部,而是专注于语言特性,一些使得这门语言变得有力和优雅的语言特性,对于一门陌生的语言,这门课程首先会引导我们看见它、使用它,然后再尽可能地作出解释,而不仅仅是停留在使用的阶段。

  • 作业的形式是编程题目,有自动打分系统,如果额外的 Challenge Problems 以及 Extra Practice Problems 都能完成的话,还是要花不少时间的。完成要求的题目并不难,思考最简洁、最优雅的代码才是最重要的。

  • 笔记其实是没多少的,为什么呢?课程中给出的 Reading Notes 真是干货满满,值得反复阅读,它提炼了老师的讲课 ppt,不过 20 页的 pdf ,内容却充实的很,而又往往前后呼应,情节跌宕起伏,怎么像是说小说一样。举个例子,它的标题是这样的:By Name vs. By Position, Syntactic Sugar, and The Truth About Tuples ,是不是很容易有种一探究竟的冲动呢。

  • 这门课上到现在直观的感受就是:循序渐进。你不用担心它讲的是废话,因为它总能解决你在前面提出的问题(如果认真去学,问题总是很多的),编程中遇到的问题,总能在某一个知识点找到解决方法,理解其中的为什么。

  • 当你遇到问题时,几乎只能用英语去表述问题并去 google ,当然结果几乎都来自于 Stack Overflow,有时还需要 The Standard ML Basis Library

  • 并不是说有用的只有我记下的那么多(而且还加工了不少),考虑到阅读材料中的一些内容已经足够精简了。如果对这门课真有兴趣,不妨去上上看。

笔记

1. All values are expressions. Not all expressions are values.

2. SML 中没有赋值语句(assignment statement),它只有 变量绑定(variable binding) 以及 函数绑定(function binding)。

Bindings are immutable. Given val x = 8+9; we produce a dynamic environment where x maps to 17. In this environment, x will always map to 17; there is no “assignment statement” in ML for changing what x maps to. That is very useful if you are using x. You can have another binding later, say val x = 19; , but that just creates a different environment where the later binding for x shadows the earlier one. This distinction will be extremely important when we define functions that use variables.

an ML program is a sequence of bindings.Each binding adds to the static environment (for type-checking subsequent bindings) and to the dynamic environment (for evaluating subsequent bindings).

3. 它的讲述模式是这样的:先给出SML内置的常见的数据结构或语法,我们可以很容易去使用。再通过介绍核心的东西(数据结构的本质)以及特定的语法,以至于我们可以自己去定义这种数据结构(list 、option 都可以通过 datatype 定义出),重要的是核心的语法是极其少的。

定义 list :

datatype my_int_list = Empty
| Cons of int * my_int_list; fun append_mylist (xs, ys) =
case xs of
Empty => ys
| Cons(x, xs') => Cons(x, append_mylist(xs', ys)); val lst = Cons(1, Cons(2, Empty)); append_mylist(append_mylist(lst, Cons(1, Cons(3, Empty))), lst);

在这里 Empty 是 my_int_list 类型的值,而 Cons 是 int * my_int_list -> my_int_list 类型的函数。

4. 为什么函数名和参数间会有一个空格呢?看到阅读材料中的代码,心中不由产生疑惑,尤其是当一个函数只有一个参数时,我们可以直接省略其中的括号,例如:

fun f x = x + 1;
f(123);
f 123;

定义一个函数,接受参数 x 返回 x+1,原本只以为是内建语法,一个语法糖而已,等到后面看到了模式匹配,才发现并不是这样。为什么不需要括号呢?因为参数本来就是一个整体,即只有一个参数。

fun f (x, y, z) = x + y + z;

看起来很正常的一个函数,其实它只是在模式匹配下的一种简化,其实它应该是这样的:

fun f(t: int * int * int) =
case t of (x, y, z) => x + y + z;

也就是说它其实是接受一个 tuple 类型的参数,将对应位置上的值分别绑定到 x, y, z 三个变量上。

也就是说,在 SML 中一个函数只会接受一个参数(one-argument function)。难怪前面说过我们要抛却以前对于 C、Java 的观念来学习这门课。

更准确地说,函数一定会接受一个参数,那么问题来了,无参数函数该怎么定义呢?其实和其它语言类似:

fun f () = "HI";

这时候必须加上一个括号了,而这个括号其实是一个 unit 类型的值。那么对应的,在调用函数的时候,应该这样:

f ();

括号是一定不能省略的,否则它输出的是这个函数的类型:val f = fn : unit -> string

其实,datatype unit = ()在 SML 中是预定义的,用的也是前面提到的 datatype 。

5. 匿名函数

如果我们想要将一个函数作为参数去传递,但并不想把它直接绑定到当前环境中,此时就可以使用匿名函数了。

首先我们可以使用简单的语法来自己模拟匿名函数:

fun f1 (addone, x) =
addone x; f1 (let fun f x = x + 1 in f end, 11);

当然,我们也可以使用关键字去定义匿名函数。

f1 (fn x => x + 1, 11)

比起简单的关键词定义,那么我们模拟的这种匿名函数是不是就没有任何意义了呢?其实不然,匿名函数最显著的特点是什么呢,匿名,那么问题来了,没有名字,怎么递归呢。想支持递归,还得有个名字。

fun f1 (f, x) =
f x; f1 (let fun f x =
case x of
0 => 1
| q => q * f (q - 1)
in f end,
7)

6. Environments and Closures

首先,不得不提 lexical scope

我们知道,在 SML 中函数就是值,而函数这个值由两部分组成,组成这个函数的代码(即函数本身),以及我们创建这个函数时的环境(environment),当我调用这个函数时,实际上使用的是创建这个函数时的环境(environment),而那个环境里则可以进行一系列的计算,并产生结果。而这个环境和调用这个函数时的环境则是隔绝的,所以我们可以说一个函数构成了 function closure。

val x = 1
fun f y =
let
val x = y + 1
in
fn z => x + y + z
end
val x = 3
val g = f 4
val t = 5
val z = g 6

z 的值为 15 。

val x = 1
fun f y =
fn z => x + y + z
val x = 3
val g = f 4
val t = 5
val z = g 6 (* 15 *)

z 的值为 11 。

7. Currying and Partial Application

简单来说,就是一个本身具有多个参数的函数(其实仍是一个参数,即一个 tuple),我们把它变成一个只接受第一个参数,并返回一个接受第二个参数的函数,更多的参数类似。例如:

fun fold1 (f, acc, xs) =
case xs of
[] => acc
| x::xs' => fold1 (f, f(acc, x), xs') fun fold2 f = fn acc => fn xs =>
case xs of
[] => acc
| x::xs' => fold2 f (f(acc, x)) xs' val sum = fn (x, y) => x + y
val l = [1, 2, 3, 4]
val res1 = fold1 (sum, 0, l)
val res2 = (((fold2 sum) 0) l)
val res3 = fold2 sum 0 l

与 Scheme 相比,SML 看起来清爽很多(如果你以前写过那种结尾带着成吨的右括号的 Scheme 程序的话)。事实上,SML的括号是可选择的,即使不加括号,它也有默认的结合规则,关键字也起到了分割代码的作用。

由于 SML 中存在默认的结合规则,计算 res3 的表达式和计算 res2 的表达式完全相同。

而一个 curried function 的定义也可以简写成:

fun fold3 f acc xs =
case xs of
[] => acc
| x::xs' => fold2 f (f(acc, x)) xs'

它们的类型:

val fold1 = fn : ('a * 'b -> 'a) * 'a * 'b list -> 'a
val fold2 = fn : ('a * 'b -> 'a) -> 'a -> 'b list -> 'a
val fold3 = fn : ('a * 'b -> 'a) -> 'a -> 'b list -> 'a

柯里化(Currying) 使得我们可以更加灵活的使用函数。

fun fold f acc xs =
case xs of
[] => acc
| x::xs' => fold2 f (f(acc, x)) xs' val is_even = fn (x, y) => x + (if y mod 2 = 0 then 1 else 0)
val count_even = fold is_even 0
val res1 = count_even [1, 2, 3, 4]
val res2 = count_even [2, 3, 4, 10, 11]

8. 关于 Value Restriction

参考

Coursera课程 Programming Languages, Part A 总结的更多相关文章

  1. Coursera课程 Programming Languages 总结

    课程 Programming Languages, Part A Programming Languages, Part B Programming Languages, Part C CSE341: ...

  2. Coursera课程 Programming Languages, Part B 总结

    Programming Languages, Part A Programming Languages, Part B Part A 笔记 碎言碎语 很多没有写过 Lisp 程序的人都会对 Lisp ...

  3. Coursera课程 Programming Languages, Part C 总结

    碎言碎语 和前面的 ML 和 Racket 感觉明显不一样了,一边学着一边觉得这真是一门奇怪的语言,有着各种奇怪的语法,不过真的算是一个奇妙的体验(相比前面的两门语言,Ruby 的学习资源多了不少). ...

  4. 【Python学习笔记】Coursera课程《Using Python to Access Web Data》 密歇根大学 Charles Severance——Week6 JSON and the REST Architecture课堂笔记

    Coursera课程<Using Python to Access Web Data> 密歇根大学 Week6 JSON and the REST Architecture 13.5 Ja ...

  5. 【C语言】Coursera课程《计算机程式设计》台湾大学刘邦锋——Week6 String课堂笔记

    Coursera课程 <计算机程式设计>台湾大学 刘邦锋 Week6 String 6-1 Character and ASCII 字符变量的声明 char c; C语言使用一个位元组来储 ...

  6. ESSENTIALS OF PROGRAMMING LANGUAGES (THIRD EDITION) :编程语言的本质 —— (一)

    # Foreword> # 序 This book brings you face-to-face with the most fundamental idea in computer prog ...

  7. Coursera课程下载和存档计划[转载]

    上周三收到Coursera平台的群发邮件,大意是Coursera将在6月30号彻底关闭旧的课程平台,全面升级到新的课程平台上,一些旧的课程资源(课程视频.课程资料)将不再保存,如果你之前学习过相关的课 ...

  8. Natural language style method declaration and usages in programming languages

    More descriptive way to declare and use a method in programming languages At present, in most progra ...

  9. The future of programming languages

    In this video from JAOO Aarhus 2008 Anders Hejlsberg takes a look at the future of programming langu ...

随机推荐

  1. 【JAVA零基础入门系列】Day12 Java类的简单应用

    俗话说的好,实践出真知,所以除了理论知识掌握扎实以外,更重要的是要多加操练,这样才能掌握核心科技. 今天我们就用刚学会的类来实践一下,目标便是完成上一篇中的剁手任务. 我们的商品类已经准备好了,代码重 ...

  2. windows中通过bat批处理打开exe文件

    1.想要运行的程序: C:\Program Files\Windows Media Player\wmplayer.exe C:\Program Files\Haihaisoft Universal ...

  3. J - Scarily interesting! URAL - 2021

    This year at Monsters University it is decided to arrange Scare Games. At the Games all campus gathe ...

  4. D - MUH and Cube Walls

    D. MUH and Cube Walls   Polar bears Menshykov and Uslada from the zoo of St. Petersburg and elephant ...

  5. windows 上rsync客户端使用方法

    1.1 获取 windows上实现rsync的软件(cwRsync) cwRsync是Windows 客户端GUI的一个包含Rsync的包装.您可以使用cwRsync快速远程文件备份和同步. 1.1. ...

  6. js和jquery实现监听键盘事件

    一.使用javascript实现 <!DOCTYPE html> <html> <head> <meta charset="utf-8"& ...

  7. React + Node 单页应用「一」前端搭建

    项目地址 预览地址 原文地址 记录最近做的一个 demo,前端使用 React,用 React Router 实现前端路由,Koa 2 搭建 API Server, 最后通过 Nginx 做请求转发. ...

  8. javascript 中遍历数组的简单方法

    在Javascript中有自带方便遍历数组的方法(此方法非彼方法不要误会哦): 1 .利用for( index in array ){}; 2.利用 array.forEach( function(e ...

  9. 《项目架构那点儿事》——快速构建Junit用例

    [前 言]按照惯例,在实际项目中我往往会对自己编写的程序进行测试,当测试通过后才能将其用于实战中,当然,编写单元测试是不可避免的,可以直接清晰的检验出 我们程序的可靠性.可只执行性,从中发现问题从而得 ...

  10. C#操作Excel知识点

    近期在使用C#操作excel,主要是读取excel模板,复制其中的模板sheet页,生成多个sheet页填充相应数据后另存到excel文件,所用到的知识点如下. 一.添加引用和命名空间 添加Micro ...