Preface

everyone can design programs

everyone can experience the satisfaction that comes with creative design.

program design —but not programming— deserves the same role in a liberal-arts education as mathematics and language skills.

每个人都可以设计程序,作为一个职业程序员,更应该学习如何设计程序。

函数设计秘诀

  • 分析问题并定义数据结构
  • 声明函数需要的输入和输出的结构,搞清楚函数计算了什么并定义函数签名
  • 举例说理函数的作用
  • 把数据定义转化为函数大纲
  • 完善函数大纲,明确目的并举例
  • 测试

Prologue

介绍来基本的 lisp 语法,包括操作符和字符串

以及 DrRacket 的使用,包含 2htdp/image 对于图片的支持

定义函数

(define (FunctionName InputName) BodyExpression)

比如:

(define (y x) (* x x))

(y 1)
(y 2)
(y 3)
(y 4)
(y 5)

条件判断

(cond
[ConditionExpression1 ResultExpression1]
[ConditionExpression2 ResultExpression2]
...
[ConditionExpressionN ResultExpressionN])

比如:
 
 (define (sign x)
 (cond
 [(> x 0) 1]
 [(= x 0) 0]
 [(< x 0) -1]))

> (sign 10)
1
> (sign -5)
-1
> (sign 0)
0

下面是一个图片滚动的示例程序,有三个版本:

来分析一下这三个版本的程序,第一个版本没有任何条件限制
 第二个版本加入了条件限制,但是不太严谨(火箭最后会有一半落在窗口外部)
 第三个版本可以正常运行(火箭正好定在窗口底部)

那么,如果需求变了,现在要求程序运行在一个 200x400 的窗口中,那么你需要在程序中修改很多的地方。为了避免这种情况,可以使用 define(define Name Expression)

v4 版本的程序把窗口的宽和高,以及火箭的图片用 define 抽取了出来,这样无论是修改窗口大小还是想修改火箭的图片,都只需要修改一个地方。

What a good programmer would never live with, however, is that the program contains the same expression three times:

观察上面的 v4 版本的程序,就会发现 (- HEIGHT (/ (image-height ROCKET) 2)) 出现了三次。

这行代码做了三件事:

  1. 定义了图片的高度
  2. 把它除以2
  3. 把得到的结果用 HEIGHT 减去

我们可以抽取这个定义

(define ROCKET-CENTER-TO-TOP
(- HEIGHT (/ (image-height ROCKET) 2)))

最后我们可以得到 v5 版本的程序:

根据 v5 版本的代码,我们可以轻松的做如下修改:

  • 把窗口改成 200x400 的大小
  • 把火箭的图片改为一个 UFO
  • 让背景色总是蓝色
  • 让火箭降落在离窗口底部 10px 的地方

这个版本还剩下一个 magic numbers50 也是一个表达式,也重复出现了,所以要消除它。

另外,目前 picture-of-rocket 所接受的参数是 h (高度),其实应该是 t(时间),根据 路程 = 时间 x 速度,我们可以添加几个定义,最终的代码如下:

我们把代表 x 轴位移的 magic number 50X 来定义。
 并且定义了速度 V,和 distance,这样我们就可以非常方便的修改火箭下落的速度了。


最后要说明,编程可不是只是知道怎么调用类库来写出计算机可以理解的语言。
 真正的程序员可以系统的解决问题,并且把解决方案映射到代码上,另外还要容易让他人理解。