Marvin's Blog【程式人生】

Ability will never catch up with the demand for it

16 Feb 2021

How To Design Programs阅读笔记【一】

How to Design Programs, Second Edition 阅读笔记,Preface,Prologue: How to Program以及部分chapter 1。

Preface

传统的编程课程教授的的是“tinker untile it works”的方式,但事情真的是真么简单就好了。

本书要教授的是“good programming”这种更具系统化的方式(systematically designed programs)。

这两种方式的差异如同蜡笔画(crayon sketches)和油画(oil paintings)的差别。

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

通过这种方式的学习,不仅可以提高编程水平,还可以学会欣赏其他形式的美学(aesthetic)。

Systematic Program Design

一个程序可以有很多功能,为了构建这些功能,需要基本的构建部块。书中以类似数学中的函数为基本构建部块。从而设计的主要目的是发掘所需要的函数,以及如何连接它们,从而实现所需功能。

标题中的Systematic Program Design混杂着两个概念:设计配方以及对配方的迭代开发。

设计的灵感来自于Michael Jackson用于COBOL程序的方法、Daniel Friedman关于递归的讨论、Robert Harper的类型理论以及Daniel Jackson的软件设计理论。

设计配方有程序级别的以及函数级别的。本书为两种类型的程序提供设计配方:GUI程序和批处理程序。

函数级别的配方就更多了。但是它们共享同一个设计过程,如下所示

  1. 从问题分析到数据定义。哪些信息需要被表示,以及如何表示。
  2. 特征,目的陈述,头部。陈述函数所能处理的数据是什么形态;并且勾勒出函数运行的目标结构;定义一个桩脚来表示函数的这些特征。
  3. 函数示例。找到一些示例,来表明函数是如何工作的。
  4. 函数模板。将数据定义翻译成函数的一个轮廓。
  5. 函数定义。根据函数的目的和已有的例子来填充函数模板。
  6. 测试。保证函数的运行能满足示例的要求。在过程中查找和发现错误。

迭代式增强(Iterative Refinement)用于应对问题的复杂性和多面性。

DrRacket and the Teaching Languages

有趣的观点:

The crucial problem is that beginners make mistakes before they know much of the language, yet programming languages always diagnose these errors as if the programmer already knew the whole language. As a result, diagnosis reports often stump beginners.

As a result, diagnosis reports often stump beginners. In contrast, learning to design programs is primarily about the study of principles and the acquisition of transferable skills.

A programming environment for professionals is analogous to the cockpit of a jumbo jet.

Racket作为教学语言,可以用来构建其他语言。DrRacket是一个对新手友好的环境。使用DrRacket可以让用户专注于数据,而不是数据处理,即不用关心数据如何加载和保存。这和model-view-controller模式有点类似。

Skills that Transfer

技能可通用有两个方面意思,一是现在有很多可编程的物件;二是提高分析能力,特别是清楚表述问题的能力。

上面提到的设计过程每个步骤设计:

  1. 分析问题声明,并用文字表述
  2. 提取和表达概要,以抽象的方式
  3. 以例子阐述概要
  4. 根据分析指定行动大纲和计划
  5. 根据目标期望来衡量结果
  6. 根据结果的得与失改进方案

每一步都要求对细节的关注,以及准确的分析,描绘和聚焦。

This Book and Its Parts

本书分为六个章节,每个章节之间有间隙(intermezzos)。书的开头和结尾有Prologue和Epilogue。

书中包含一个导览图,阐述各个章节之间的关系。

The Differences

和第一版的区别

  1. 回应了整个程序设计和细分函数设计的区别。第二版聚焦于两类程序:event-driven以及批处理
  2. 整体程序设计通常自上而下规划,以及而上构建。前者产生一个对函数的期待列表,后者实现函数。
  3. 实现函数的时候需要使用到设计配方。
  4. 强调design by composition。函数之间如何打配合。
  5. 强烈依赖于DrRacket提供的学习环境。
  6. 放弃了强令式(imperative)编程。部分内容移到系列第二卷:How to Design Components
  7. techpacks可以通过require的方式在代码中获得

Acknowledgments from the First Edition

Acknowledgments

Prologue: How to Program

Arithmetic and Arithmetic

DrRacket的定义窗口可以直接插入图片,感觉不错。通过(require 2htdp/image),还可以直接在图片上执行image-width和image-height等操作。还可以通过(circle 10 "solid" "red")来直接生成图形。下面是另一个例子:

(overlay (circle 5 "solid" "red")
           (rectangle 20 20 "solid" "blue"))

简而言之,BSL(初级学生语言)运行做算术操作。操作的对象不仅可以是数字、字符串、布尔值,甚至还可以是图像。计算意味着确定表达式的值,表达式涉及的值的类型可以是上述描述的类型之一。

Inputs and Output

上个章节举的arithmetic是一个狭义编程例子。广义的编程可能要处理比arithmetic更多的数据类型。

本章以动画的例子介绍函数的输入输出。

Many Ways to Compute

做动画的时候会弹出一个小窗口,还挺有意思的。

One Program, Many Definitions

如何用define定义常量。

Better than pondering is doing.

One More Definition

比上个章节多增加了一个函数。

You Are a Programmer Now

基本的招式都见过了。

Not!

认同下列见解:

Acquiring the mechanical skills of programming—learning to write expressions that the computer understands, getting to know which functions and libraries are available, and similar activities—isn’t helping you all that much with real programming. If it were, you could equally well learn a foreign language by memorizing a thousand words from the dictionary and a few rules from a grammar book.

以及下列见解:

A good program reflects the problem statements and its important concepts. It comes with a concise self-description. Examples illustrate this description and relate it back to the problem. The examples make sure that the future reader knows why and how your code works. In short, good programming is about solving problems systematically and conveying the system within the code.

I Fixed-Size Data

程序设计的一个工作是用数据表示信息。如何区分和表示数据是一个重要的问题。为了容易描述数据,要有一些元始类型的数据(atomic data),并且这些元始类型数据可以支持一定的操作。

We equate “organizing thoughts” with design.

1 Arithmetic

下面的子章节介绍四种元始数据类型:numbers, strings, images, 以及boolean values。元始数据类型具有原子性,即不可细分,但可组合。元始数据上支持预定义的简要操作(primitive operations)

1.1 The Arithmetic of Numbers

BSL对于number提供以下操作:+, -, *, /, abs, add1, ceiling, denominator, exact->inexact, expt, floor, gcd, log, max, numerator, quotient, random, remainder, sqr, tan.

对于数字,有精确和非精确之区分。简单的说,精确数用来表示有理数,非精确数用来表示有理数之外的数。

1.2 The Arithmetic of Strings

学到一个单词innards:internal organs collectively (especially those in the abdominal cavity。

虽然计算机内部实现涉及大量的比特和字节运算,但是使用上主要还是要针对信息进行抽象。信息具有不同的形态,需要不同的抽象,即便这些抽象最终都要编码成比特或者字节。

1.3 Mixing It Up

看到算术运算和字符串运算的相似性。

1.4 The Arithmetic of Images

看到算术运算和图片运算的相似性。

1.5 The Arithmetic of Booleans

介绍逻辑运算的三个操作符:or, and, not

1.6 Mixing It Up with Booleans

介绍布尔值在条件控制中的应用。

1.7 Predicates: Know Thy Data

如何判断数据的类型?使用 number?, string?, image?, boolean?, integer?, rational?, real?, complex?, exact?, inexact? 等操作。

2 Functions and Programs

除了“算术”以外,“代数”也很重要。

Functions

BSL中只有两种定义:

  • 常量定义
  • 函数定义

函数定义的形式如:

(define (FunctionName Variable ... Variable)
  Expression)

函数的形式参数,指代的是未知的输入数据。只有这样,函数才可以应用在不同的数据之上。函数被调用而执行,调用的时候要提供实际参数。

Computing

演示了stepper的使用。

Composing Functions

Global Constants

Programs

2htdp/batch-io 添加了read-file和write-file函数。

3 How to Design Programs

(未完待续)

到这里,感觉这本书是给完全没有编程经验的人写的。对于有经验的,略显繁琐。

Categories