1
2
3
4
5
6
#include <iostream>
int main()
{
std::cout << "Hello, world!\n";
}
大多数的程序员,编程入门课都是从hello world开始,上面的代码是c++版本的。代码里包含了语言里的类型(int),库(iostream),函数(main、cout),变量(Hello, world!\n),作用域(一对大括号)。麻雀虽小五脏俱全!
代码应当是符合人的阅读习惯的,它的语义应当明确。函数名称、变量名称所表达的含义应当是确定的、没有歧义的。一门语言里除了字面上的符号,如前面的int main,还有它内部的运行规则,比如c++一段代码的结束必须以分号结尾、函数必须用一对大括号包含。
我们在初中学习的代数,用字母变量来表示数学对象。其中的运算规则,在大多数的编程语言里也是一样的。除了基本的四则运算,还有交换律、结合律。
下面的代码里,a、b、c就是代数对象。
1
2
3
int a = 1;
int b = 2;
int c = a + b;
在代码里我们命名了很多变量,对这些变量运用了一些规则,达到我们的业务目的。代码里的函数和数学里的函数看起来很相似,却不能等价。比如数学里的函数

是一条连续的抛物线,x的取值范围是实数域,包含无穷个点。但是编程语言里的类型系统,无论是整型(int、long),还是浮点型(float、double),它们取值范围的都是有限的。这个范围可以用公式表达出来。对于32位的int而言,

如果用32位int来画这个函数,是一条不连续的,由散列点组成的抛物线。
除了代数的四则运算,在编程的世界里,还有一样我们很习以为常的东西,就是拟物。
1
2
3
a = 风扇
b = 美女
c = 河流
我们用代码里的变量来指代现实世界里的物体、生命、概念,这也是很多语言叫面向对象的原因。这些变量可以有自己的行为,有自己的属性。比如风扇可以有不同的风力,有小风扇,有立式风扇。美女也有胖有瘦,有能言善辩的,也有沉默寡言的。河流可以滔天巨浪,也可以潺潺小溪。这些变量之间往往可以互动,产生行为,遵循一定的规则,比如美女落到河里没准会淹死。
前面粗略讲了些东西,说明了编程语言一些不可或缺的东西。一是变量,也就是代数符号。二是规则,这些变量必须遵守的约束,比如四则运算、自然规律。三是相容性,这点前面没有讲,意思就是这些变量按照规则在系统里运行,不会出现矛盾的情况,比如美女化身超人,把世界毁灭,把系统搞崩溃。相容性大多数是符合我们人的直觉的。这些看起来合理的东西构成了编程语言的骨骼。
编程语言的出现是为了解决现实世界里的问题,它的灵魂是数学。能不能解决好问题就看程序员的创造力和想象力了。
前面说了编程语言不可或缺的三样东西,如果往深一点说,它们就是数学里大名鼎鼎的形式主义所必备的东西。

用形式主义所构造的系统,不需要关注它的规则在现实世界里是否有真实对应关系,只要这个系统是相容的、完备的。比如前面说了美女化身超人毁灭世界,只要有英雄来阻止就可以了。1+2=5,这个规则也可以成立,只要系统不矛盾就行。用编程语言去开发游戏,游戏里各种角色人物,可以拥有不同的能力,它们可以独立存在,玩家按照规则就可以畅玩了。
大多数的编程语言都不过是形式主义的傀儡,如果你知道了Java的灵魂归处,再去学Rust、Python,那是易如反掌。我并不是大放厥词,而是有理有据。披着美丽外衣的各种语言,它们的表达形式都太过类似。