本书关注的是编程概念和使用它们的技巧,而不是编程语言。这些概念是基于计算模型(computation model)来组织的。计算模型基于它的核心语言(kernel language)。核心语言通过添加一个接着一个的概念来渐进式的呈现。这样就可以清楚不同模型之间的深层关系。通常添加一个新的概念就会使编程产生很大的不同。比如,添加destructive assignment (explicit state)到函数式编程中就会变成面向对象编程。
如何确定添加什么概念?主要的标准是the creative extension principle。简单来说,当程序因为technical reasons(unrelated to the problem being solved)变得复杂时,为了使得程序保持简洁,我们就添加一个新的概念到kernel language中。
这种kernel language方式的一个好处就是我们可以在同一个程序中使用不同的模型,这就叫做多范式编程(multiparadigm programming)。这是很自然的,因为它就是根据问题来使用合适的概念,而与概念来自哪个计算模型无关。多范式编程是一个old idea,像Lisp和Scheme的设计者就长期主张相似的观点。
本书的目标是学习编程和设计抽象。编程是扩展或者改变系统功能的行为。抽象具有用途广泛性。
学习编程有两种方式:The computation-based approach和The logic-based approach。前者是使用真实的系统来编程运行得到结果,后者不关心运行而是程序的性质,是更高的抽象,程序是遵循逻辑法则的数学构建。本书和SICP一样使用第一种交互方式,使用的系统是Mozart。
单模型的局限
- 面向对象语言过多地使用状态和继承,对象默认是状态性的。这看起来简单且直观,实际上却使得编程复杂化了,比如它使得并发变得困难(8.2)。设计模式经常就继承来说明。很多时候,简单高阶的编程技巧就足够了(7.4.7)。继承还经常被误用,比如面向对象图形用户接口推荐使用继承来扩展具有特定应用功能的generic widget classes(比如Java的Swing),这就与separation of concerns相反。
- 函数式编程过多地使用高阶编程。典型例子是Monads和Currying。函子(Monads)通过贯穿整个程序来给状态编码,这使得程序更加复杂却没有做到真正的explicit state的模件性(modularity properties)(4.7)。柯里化(Currying)指的是将原来接受两个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数为参数的函数。缺点是不好判断函数是否拥有它的全部参数还是仍然被柯里化。
- 在Prolog传统中的逻辑语言过多的使用Horn clause的语法和搜索。