一、构成程序的基本元素
程序的构成有两项要素,即数据data和函数function。构思程序起于青萍之末的原始材料数字,扶摇直上到“变量”,到表达力飞跃的“函数”,又及创造智能的“条件判断”,进而到自动化的“迭代与递归”。最后作为思考工具,我们将函数作为“思维抽象体“看待,而非“运算执行实体”。
下面,我们将一一展开叙述:
1.数学表达式 Expression
JavaScript使用完全符合我们直觉的infix中序表达式:
// 加减乘除
> 173 + 373
546
> 1002 - 457
545
> 8 * 43
344
> 11 / 3
3.6666666666666665
> 11.0 / 4
2.75
> 10 / 2
5
> 3.7 + 10
13.7
//模除
> 11 % 3
2
//乘方
> 2 ** 11
2048
//组合
> (1 - ((5 / 2) * 4)) + 3
-6
2.定义常量与变量
以抽象的变量指代具体的对象,是程序迈开步伐走向抽象的第一步:
//定义常量
> const pi = 3.1415926 //const for constant 不变的值
undefined
//定义变量
> var radius = 11 //var for variable 变化的值
undefined
> pi * radius ** 2
380.1327046
> var area = pi * radius ** 2
undefined
> area
380.1327046
> var circumference = 2 * pi * radius
undefined
> circumference
69.1150372
3.函数 Function
函数是程序走向走向的第二步,表达力骤然飙升。
> function square(x) {
... return x ** 2;
... }
undefined
> square(11)
121
定义函数的格式为:
function name(parameters) { return expression; }
往函数中传入表达式:
> square(11 + 13);
576
组合函数求勾股定理:
> function sum_of_squares(x,y) {
... return square(x) + square(y);
... }
> sum_of_squares(3, 4)
25
在此基础上,进一步构建:
> function f(a) {
... return sum_of_squares(a+1, a*2);
... }
undefined
> f(7)
260
4.条件判断表达式 Conditional Expressions and Predicates
条件判断赋予程序以”智能“!!!
predicate ? //predicate 这个术语用得最妙
consequent-expression :
alternative-expression
求绝对值:
function abs(x) {
return x >= 0 ? x : -x;
}
> abs(-5);
5
条件判断除了基本的数字运算符 >=, >, <, <=, ===, and !==之外,还有表达力更上一层楼的逻辑运算符:(注意相等与不等的判断)
> expression1 && expression2
> expression1 || expression2
> ! expression
于是,定义域15<x<20可以表达为:
x > 15 && x < 20
注意逻辑运算符&&的优先级”低于“算术运算符<>
小试牛刀:
> function greater_or_equal(x, y) {
... return x > y || x === y;
... }
> function greater_or_equal_alter(x, y) {
... return ! (x < y);
... }
测试Nomal-Order与Application-Order:
> function p() {return p();}
> function test(x, y) {
... return x === 0 ? 0 : y;
... }
> test(0, p())
Uncaught RangeError: Maximum call stack size exceeded
at p (REPL80:1:15)
at p (REPL80:1:22)
at p (REPL80:1:22)
at p (REPL80:1:22)
at p (REPL80:1:22)
at p (REPL80:1:22)
at p (REPL80:1:22)
at p (REPL80:1:22)
at p (REPL80:1:22)
at p (REPL80:1:22)
5.迭代与递归
现在是函数展现“真正实力”的时候了。
我们尝试应用循环结构求平方根,并且采用牛顿迭代算法:
牛顿求平方根法用的是‘连续逼近’的思路 “successive approximations”。我们首先瞎猜一个y作为x的平方根,然后在这个瞎猜的基础上更好的瞎猜,不断地接近平方根的真实值。这个better-guess为前面的瞎猜值与x/y的平均值,分布过程展示为:
牛顿迭代法
> function sqrt_iter(guess, x) {
... return good_enough(guess, x)
... ? guess
... : sqrt_iter(improve(guess, x), x);
... }
> function improve(guess, x) {
... return average(guess, x/guess);
... }
> function average(x, y) {
... return (x + y) / 2;
... }
> function good_enough(guess, x){
... return abs(square(guess) - x) < 0.001;
... }
> function sqrt(x) {
... return sqrt_iter(1, x);
... }
> sqrt(9)
3.00009155413138
求立方根的公式(牛顿迭代法求立方根,基于以下公式):
(x/y**2 + 2y) / 3
function abs(x) {
return x >= 0 ? x : -x;
}
function cube(x) {
return x * x * x;
}
function good_enough(guess, x) {
return abs(cube(guess) - x) < 0.001;
}
function div3(x, y) {
return (x + y) / 3;
}
function improve(guess, x) {
return div3(x / (guess * guess), 2 * guess);
}
function cube_root(guess, x) {
return good_enough(guess, x)
? guess
: cube_root(improve(guess, x), x);
}
//对仗真是工整呀。
cube_root(3, 27);
6.函数作为抽象的思维工具 Functions as Black-Box Abstractions
应用一个尚未定义的函数时,我们思维里是“函数的抽象”而非“函数的实体”。
下面两个函数,虽然实现方法不同,但均实现同样的目的。
function square(x) {
return x * x;
}
function square(x) {
return math_exp(double(math_log(x)));
}
function double(x) {
return x + x;
}
局域变量Local-Names
function square(x) {
return x * x;
}
function square() {
return y* y;
}
变量名不同,运算相同。
函数的嵌套 Internal definitions declarations and block structure
function abs(x) {
return x >= 0 ? x : -x;
}
function square(x) {
return x * x;
}
function average(x,y) {
return (x + y) / 2;
}
function sqrt(x) {
function good_enough(guess, x) {
return abs(square(guess) - x) < 0.001;
}
function improve(guess, x) {
return average(guess, x / guess);
}
function sqrt_iter(guess, x) {
return good_enough(guess, x)
? guess
: sqrt_iter(improve(guess, x), x);
}
return sqrt_iter(1, x);
}
sqrt(5);
7.收尾总结
程序的构成有两项要素,数据data和函数function。构思程序起于青萍之末的primitive-date数字,扶摇螺旋上升到“变量”,表达力飞跃的“函数”,创造智能的“条件判断”,进而到自动化的迭代与递归。最后作为思考工具,我们将函数作为“思维抽象体“看待,而非“运算执行实体”。
从这一节开始,我们将踏上思维的饕餮盛宴。