SICP 常被成为魔法书、巫师书、紫皮书,起源于 MIT CS6.001,从 1980 开到 2008 年。1986 年,该课程的两位老师(也是这本书的作者) Hal Abelson 和 Gerald Jay Sussman 给惠普员工做了一次全套讲座,讲座全程录像,也是这门课在历史上留下的唯一的视频资料(绝对渣画质)。
本书可以免费在线阅读,机械工业出版社出过中文版。讲座用 MIT-Scheme(Lisp 的一种方言),函数式编程语言,所有函数都没有任何副作用,纯粹考返回值。
Brian Harvey 加州大学伯克利分校
2011 年,为了庆祝麻省理工学院(MIT)建校 150 周年,《波士顿环球报》列出了在那里开发的最重要的创新成果。他们邀请我解释 SICP(《计算机程序的构造和解释》)的重要性,这是我发给他们的内容:
SICP 在许多方面都具有革命性。最重要的是,它极大地提高了计算机科学导论课程的智力含量标准。在 SICP 出现之前,大多数计算机科学入门课程几乎都只是在学习某种编程语言的细节。而 SICP 则要求我们跳出细节,学习关于编程过程的整体思维方式。它将注意力集中在抽象这一核心思想上——从具体问题中寻找通用模式,并构建体现每种模式的软件工具。它大量运用了“函数即数据”的思想,这个概念虽然起初难以掌握,但一旦学会,就会发现它无比强大。(这是和微积分类似的想法,只是换了一种形式——哪怕在此前数学成绩优异的学生,也会发现大学微积分异常困难。)SICP 在一门入门课程中涵盖了三种不同的编程范式(函数式、面向对象和声明式),而大多数其他课程甚至连一种范式都没有系统地讨论。
另一项革命性创新是选择了 Scheme 作为教学语言。直到今天,大多数计算机科学入门课程仍然使用当时“流行”的语言:从 Pascal 到 C,再到 C++、Java、Python。Scheme 从未在工业界广泛应用,但它是教学计算机科学的理想语言。首先,它的符号系统非常简单统一。其他语言对变量赋值用一种写法,对条件执行用另一种写法,循环又有两三种写法,函数调用则再用另一套语法。而用这些语言教学的课程,往往至少要花一半的时间去教语法。而在我基于 SICP 的课程中,我们只在第一堂课用一个小时讲解语法,这就足够了;整个学期,我们都专注在学习理念,而不是语法。其次,Scheme 尽管简洁,却非常灵活,让我们能够探索不同的编程范式,尤其是能让学生理解面向对象编程的实现原理,因此 OOP 语言对他们来说不再像“魔法”一样神秘。Scheme 是 Lisp 的一个方言,非常擅长处理“函数即数据”的概念,但它比专业编程中常用的 Lisp 更加简化,减少了许多额外的复杂性。Abelson 和 Sussman 很有勇气选择用这样一种最适合教学的语言,而无视业界要求学生掌握其它语言的声音。他们认为,一旦你掌握了核心思想,再学一种编程语言不过是一个周末的任务。我也这么认为。我告诉学生:“你将来工作时最常用的编程语言现在还没被发明出来,所以我们无法教你。我们要教你的是,如何在新语言出现时迅速学会它。”
最后,SICP 对大学一年级新生的能力充满信心。SICP 学生能够编写编程语言的解释器,这在其他课程里通常被认为是大三甚至大四学生才能完成的任务。SICP 教材本身也并不容易阅读;它没有现代教材常见的边栏、彩色框、趣味插图,不是为注意力分散的学生设计的。它没有重复性的练习,每一道题目都传授了重要的新思想。它用词严谨,但细细研读绝对值得;书中每一句话都很重要。
从统计上来看,基于 SICP 的课程只占少数。但这本书的影响力早已超出这个范围。许多后来的教材,作者都明确表示要向 SICP 看齐。Scheme 作为教学语言的应用也被推广到了从初中到研究生不同层次的课程。即使是更主流的课程,也开始重视编程范式的概念,尽管它们大多集中在面向对象编程上。计算机科学应关注思想,而不仅仅是编程实践,这种理念也扩展到了非技术领域,包括计算的背景和社会影响。
SICP 拥有非比寻常的生命力。一般来说,计算机科学入门教材的生命周期仅与其所用语言的流行程度同步。而 SICP 已经畅销了 25 年以上,且至今未绝版。计算机领域在此期间发生了翻天覆地的变化,从大型机到个人电脑再到移动互联网,但背后的核心思想始终不变,而这些思想都被 SICP 所准确传达。
我从 1987 年开始教授基于 SICP 的课程。课程在这期间逐步演变,我们增加了并行、并发控制、用户界面设计和客户端/服务器架构等内容。但课程的核心仍然没有改变。每隔五年,总有教师提议换成“语言 X”作为第一门课的教学语言;而我每次都会说:“等有人用语言 X 写出世界上最好的计算机科学教材时,那没问题。”到目前为止,系里每次都投票决定继续使用 SICP。很快就能知道这门课程能否在我退休后继续存在。
(注:不能。伯克利新的计算机科学入门课改用了 Python,但在讲义中仍尽量保持了 SICP 的理念(和部分文本)。)
最近的争论更加激烈,因为 MIT 对其 EECS 低年级课程体系进行了大幅度重构。校外的人通常总结为“MIT 改用 Python”,但这其实是误解。MIT 的真正决定是从“按主题组织课程”(先学编程范式,再学电路,再学信号处理,再学计算机架构)转向“按应用组织课程”(比如设计并编程一个机器人,再设计并编程一个手机)。整个课程体系都重构了,编程语言的选择只是其中最次要的部分。这种“应用优先”的方式更难教,因为每门课都需要电气工程和计算机科学教师的合作。也许将来这种方法会像 SICP 当年那样引发新的革命,但目前还没有。
根据我的经验,只有极少数学生在上课时意识到他们学到了多少。然而,在全体计算机科学专业学生的调查中,这门课却成为回忆中最受欢迎的课程之一。我经常收到多年前的学生来访或邮件,告诉我他们在工作中用到了当年觉得“学院派、脱离现实”的想法。谷歌的 MapReduce 软件采用了函数式编程的思想,实现了数据并行,这也帮助消除了“象牙塔”的声誉问题。
SICP 真的是一本好书,一本不可多得的内功心法,一定要读,一定要读,一定要读。
两个字总结 SICP:内功。在编程界,SICP 毫无疑问是一本顶级内功。拉到一个极高的视角,一边分解程序,一边教你如何正确的构建和编写程序。具体来说,SICP 教你如何熟练运用抽象以及程序如何运行。抽象不就是封装函数吗?不就是隐藏实现吗?程序不就是解释或者编译运行吗?但是要真正理解和掌握这些东西需要大量的训练。知道和掌握是两个截然不同的概念,在这个时代我们知道的太多,掌握的太少。
SICP 学习经验就是:首先理解作者思路,把一切看做纸老虎,然后坚持到底。
SICP 的最大缺点就是长得太丑。随便一翻就是各种数学公式、加法器、数理逻辑,还没看就吓跑一批人。不过这其实是纸老虎。作者的目的是教你一些知识,而不是为了难住你。这是“SICP 第一定律”,在学习过程中一定要牢记这句话。
SICP 里面涉及到的知识有:向量、矩阵、各种数学公式(求平方根、立方根、导数、不动点、微积分……)、数字电路、数理逻辑、机器语言、并发、解释器、编译器。在学习的过程中,经常是上一页还在实现微积分,下一页就开始讲电路;上一页还在解数理逻辑,下一页就开始写编译器,内容跨度之大令人发指。这些东西其实都是给你举例子,真正的目的是教你编程思想。只不过呢,SICP 是 MIT 的教材,MIT 里众神云集,给他们写的教材自然也不能太简单。
在学 SICP 的过程中,我收获了一个重要的经验,那就是:一鼓作气。看起来完美的计划为什么总是失败?不是你计划得不好,不是你除法用得不溜,而是因为战线拖的太长。生活有太多无法预料的事,战线长导致很大的问题是低效。每天 15 页,看似分摊了任务,无形之中增加了很多上下文切换和环境初始化的开销。每天你都需要先回忆之前的内容,然后继续看。如果题目用到了之前的知识(这在 SICP 中很常见),你不得不返回去继续阅读。这反过来又增加了失败的概率。因此,不要再浪费时间做无用的计划,从现在开始,一鼓作气,用尽一切时间去学!
中文版:https://composingprograms.netlify.app/
https://github.com/csfive/composing-programs-zh