❏ 站外平台:

王垠:数学和编程

作者: 王垠

| 2015-12-10 10:26   评论: 24 收藏: 5    

好些人来信问我,要成为一个好的程序员,数学基础要达到什么样的程度?十八年前,当我成为大学计算机系新生的时候,也为同样的问题所困扰。面对学数学,物理等学科的同学,我感到自卑。经常有人说那些专业的知识更加精华一些,难度更高一些,那些专业的人毕业之后如果做编程工作,水平其实比计算机系毕业的还要高。直到几年前深入研究程序语言之后,对这个问题我才得到了答案和解脱。由于好多编程新手遇到同样的困扰,所以我想在这里把这个问题详细的阐述一下。

(配图来自 wallchan.com)

数学并不是计算机科学的基础

很多人都盲目的认为,计算机科学是数学的一个分支,数学是计算机科学的基础,数学是更加博大精深的科学。这些人以为只要学会了数学,编程的事情全都不在话下,然而事实却并非如此。

事实其实是这样的:

  • 计算机科学其实根本不是数学,它只不过借用了非常少,非常基础的数学,比高中数学还要容易一点。所谓“高等数学”,在计算机科学里面基本用不上。
  • 计算机是比数学更加基础的工具,就像纸和笔一样。计算机可以用来解决数学的问题,也可以用来解决不是数学的问题,比如工程的问题,艺术的问题,经济的问题,社会的问题等等。
  • 计算机科学是完全独立的学科。学习了数学和物理,并不能代替对计算机科学的学习。你必须针对计算机科学进行学习,才有可能成为好的程序员。
  • 数学家所用的语言,比起常见的程序语言(比如C++,Java)来说,其实是非常落后而糟糕的设计。所谓“数学的美感”,其实大部分是夜郎自大。
  • 99%的数学家都写不出像样的代码。

数学是异常糟糕的语言

这并不是危言耸听。如果你深入研究过程序语言的理论,就会发现其实数学家们使用的那些符号,只不过是一种非常糟糕的程序语言。数学的理论很多是有用的,然而数学家门用于描述这些理论所用的语言,却是纷繁复杂,缺乏一致性,可组合性composability,简单性,可用性。这也就是为什么大部分人看到数学就头痛。这不是他们不够聪明,而是数学语言的“设计”有问题。人们学习数学的时候,其实只有少部分时间在思考它的精髓,而大部分时间是在折腾它的语法。

举一个非常简单的例子。如果你说cos2θ表示(cos θ)2,那么理所当然,cos-1θ就应该表示1/(cos θ)了?可它偏偏不是!别被数学老师们的教条和借口欺骗啦,他们总是告诉你:“你应该记住这些!” 可是你想过吗:“凭什么?” cos2θ表示(cos θ)2,而cos-1θ,明明是一模一样的形式,表示的却是arccos θ。一个是求幂,一个是调用反函数,风马不及,却写成一个样子。这样的语言设计混淆不堪,却喜欢以“约定俗成”作为借口。

如果你再多看一些数学书,就会发现这只是数学语言几百年累积下来的糟粕的冰山一角。数学书里尽是各种上标下标,带括号的上标下标,x,y,z,a,b,c,f,g,h,各种扭来扭去的希腊字母,希伯来字母…… 斜体,黑体,花体,双影体,……用不同的字体来表示不同的“类型”。很多符号的含义,在不同的子领域里面都不一样。有些人上一门数学课,到最后还没明白那些符号是什么意思。

直到今天,数学家们写书仍然非常不严谨。他们常犯的一个错误是把x2这样的东西叫做“函数”function。其实x2根本不是一个函数,它只是一个表达式。你必须同时指明“x是参数”,加上x2,才会成为一个函数。所以正确的函数写法其实看起来像这样:f(x) = x2。或者如果你不想给它一个名字,可以借用lambda calculus的写法,写成:λx.x2

可是数学家们灰常的喜欢“约定俗成”。他们定了一些不成文的规矩是这样:凡是叫“x”的,都是函数的参数,凡是叫“y”的,都可能是一个函数…… 所以你写x2就可以表示λx.x2,而不需要显式的写出“λx”。殊不知这些约定俗成,看起来貌似可以让你少写几个字,却造成了许许多多的混淆和麻烦。比如,你在Mathematica里面可以对 x2+y 求关于x的导数,而且会得到 y'(x) + 2x 这样蹊跷的结果,因为它认为y可能是一个函数。更奇怪的是,如果你在后面多加一个a,也就是对x2+y+a求导,你会得到 2x!那么 y'(x) 到哪里去了?莫名其妙……

相对而言,程序语言就严谨很多,所有的程序语言都要求你必须指出函数的参数叫什么名字。像x2这样的东西,在程序语言里面不是一个函数function,而只是一个表达式expression。即使 JavaScript 这样毛病众多的语言都是这样。比如,你必须写:

function (x) { return x * x }

那个括号里的(x),显式的声明了变量的名字,避免了可能出现的混淆。我不是第一个指出这些问题的人。其实现代逻辑学的鼻祖Gottlob Frege在一百多年以前就在他的论文“Function and Concept”里批评了数学家们的这种做法。可是数学界的表达方式直到今天还是一样的混乱。

很多人学习微积分都觉得困难,其实问题不在他们,而在于莱布尼兹Leibniz。莱布尼兹设计来描述微积分的语言(∫,dx, dy, ...),从现代语言设计的角度来看,其实非常之糟糕,可以说是一塌糊涂。我不能怪莱布尼兹,他毕竟是几百年前的人了,他不知道我们现在知道的很多东西。然而古人的设计,现在还不考虑改进,反而当成教条灌输给学生,那就是不思进取了。

数学的语言不像程序语言,它的历史太久,没有经过系统的,考虑周全的,统一的设计。各种数学符号的出现,往往是历史上某个数学家有天在黑板上随手画出一些古怪的符号,说这代表什么,那代表什么,…… 然后就定下来了。很多数学家只关心自己那块狭窄的子领域,为自己的理论随便设计出一套符号,完全不管这些是否跟其它子领域的符号相冲突。这就是为什么不同的数学子领域里写出同样的符号,却可以表示完全不同的涵义。在这种意义上,数学的语言跟Perl(一种非常糟糕的程序语言)有些类似。Perl把各种人需要的各种功能,不加选择地加进了语言里面,造成语言繁复不堪,甚至连Perl的创造者自己都不能理解它所有的功能。

数学的证明,使用的其实也是极其不严格的语言——古怪的符号,加上含糊不清,容易误解的人类语言。如果你知道什么是Curry-Howard Correspondence就会明白,其实每一个数学证明都不过是一段代码。同样的定理,可以有许多不同版本的证明(代码)。这些证明有的简短优雅,有的却冗长繁复,像面条一样绕来绕去,没法看懂。你经常在数学证明里面看到“未定义的变量”,证明的逻辑也包含着各种隐含知识,思维跳跃,非常难以理解。很多数学证明,从程序的观点来看,连编译都不会通过,就别提运行了。

数学家们往往不在乎证明的优雅性。他们认为只要能证明出定理,你管我的证明简不简单,容不容易看懂呢。你越是看不懂,就越是觉得我高深莫测,越是感觉你自己笨!这种思潮到了编程的时候就显出弊端了。数学家写代码,往往忽视代码的优雅性,简单性,模块化,可读性,性能,数据结构等重要因素,认为代码只要能算出结果就行。他们把代码当成跟证明一样,一次性的东西,所以他们的代码往往不能满足实际工程的严格要求。

数学里最在乎语言设计的分支,莫过于逻辑学了。很多人(包括很多程序语言专家)都盲目的崇拜逻辑学家,盲目的相信数理逻辑是优雅美好的语言。在程序语言界,数理逻辑已经成为一种灾害,明明很容易就能解释清楚的语义,非得写成一堆稀奇古怪,含义混淆的逻辑公式。殊不知其实数理逻辑也是有很大的历史遗留问题和误区的。研究逻辑学的人经常遇到各种“不可判定”undecidable问题和所谓“悖论”paradox,研究几十年也没搞清楚,而其实那些问题都是他们自己造出来的。你只需要把语言改一下,去掉一些不必要的功能,问题就没了。但逻辑学家们总喜欢跟你说,那是某天才老祖宗想出来的,多么多么的了不起啊,不能改!

一阶逻辑first-order logic这样的东西,你可以写出一些毫无意义的语句。逻辑老师们会告诉你,记住啦,这些是没有意义的,如果写出来这些东西,是你的问题!他们没有意识到,如果一个人可以用一个语言写出毫无意义的东西,那么这问题在于这个语言,而不在于这个人。一阶逻辑号称可以“表达所有数学”,结果事实却是,没有几个数学家真的可以用它表达很有用的知识。到后来,稍微明智一点的逻辑学家们开始研究这些老古董语言到底出了什么毛病,于是他们创造了Model Theory这样的理论。写出一些长篇大部头,用于“验证”这些逻辑语言的合理性。这些问题在我看来都是显而易见的,因为很多逻辑的语言根本就不是很好很有用的东西。去研究它们“为什么有毛病”,其实是白费力气。自己另外设计一个更好语言就完事了。

在我看来,除了现代逻辑学的鼻祖Gottlob Frege理解了逻辑的精髓,其它逻辑学家基本都是照本宣科,一知半解。他们喜欢把简单的问题搞复杂,制造一些新名词,说得玄乎其玄灵丹妙药似的。如果你想了解逻辑学的精华,建议你看看Frege的文集。看了之后你也许会发现,Frege思想的精华,其实已经融入在几乎所有的程序语言里了。

编程是一门艺术

从上面你也许已经明白了,普通程序员使用的编程语言,就算是C++这样毛病众多的语言,其实也已经比数学家使用的语言好很多。用数学的语言可以写出含糊复杂的证明,在期刊或者学术会议上蒙混过关,用程序语言写出来的代码却无法混过计算机这道严格的关卡。因为计算机不是人,它不会迷迷糊糊的点点头让你混过去,或者因为你是大师就不懂装懂。代码是需要经过现实的检验的。如果你的代码有问题,它迟早会导致出问题。

计算机科学并不是数学的一个分支,它在很大程度上是优于数学,高于数学的。有些数学的基本理论可以被计算机科学所用,然而计算机科学并不是数学的一部分。数学在语言方面带有太多的历史遗留糟粕,它其实是泥菩萨过河,自身难保,它根本解决不了编程中遇到的实际问题。

编程真的是一门艺术,因为它符合艺术的各种特征。艺术可以利用科学提供的工具,然而它却不是科学的一部分,它的地位也并不低于科学。和所有的艺术一样,编程能解决科学没法解决的问题,满足人们新的需求,开拓新的世界。所以亲爱的程序员们,别再为自己不懂很多数学而烦恼了。数学并不能帮助你写出好的程序,然而能写出好程序的人,却能更好的理解数学。我建议你们先学编程,再去看数学。

如果你想了解更多关于数学语言的弊病以及程序语言对它们的改进,我建议你看看这个Gerald Susman的讲座



最新评论

来自四川成都的 Chrome 79.0|Windows 10 用户 2019-12-29 21:17 1 回复
我差点就信了,真的.
hazdzz [Firefox 45.0|Mac 10.9] 2016-04-10 02:07 11 回复
一本正经地胡说八道
jack.pc [Firefox 44.0|Ubuntu] 2016-02-16 10:00 8 回复
计算机科学好比是金字塔,金字塔的基础决定他的高度。数学,物理学,电子学,等等都是他的基石之一。这些基石决定你将来是程序员还是计算机科学家。
logicwei [Maxthon 1.0|GNU/Linux] 2016-01-31 19:43 5 回复
数学符号被设计的很乱,那是因为真理都是未知的,只能发现一个东西然后给数学符号增添一点东西,而程序语言的功能都是很明确的,人们在设计的时候能够完全掌控,我要实现什么功能,应该添加什么符号.所以说,像题主这么说的话就太偏激了
来自广东广州的 WeChat 6.3|iOS 8.3 用户 2015-12-29 08:20 6 回复
看来你的编程水平很低啊,数学是工具,你要用它来描述复杂的自然,再化成代码,数学的主要作用是实现算法,不然AUTOCAD这种软件怎么来的,就你那点水平还是回家歇着吧!
来自上海的 Chrome 47.0|Windows 7 用户 2015-12-18 16:29 8 回复
为什么学个皮毛,一知半解,就敢胡说八道,信口雌黄的人,这么多
来自上海的 Chrome 47.0|Windows 7 用户 2015-12-18 16:25 4 回复
胡说八道,你说懂了数学了吗,就瞎说
[1]
来自甘肃白银的 Chrome 31.0|Windows 7 用户 发表于 2015-12-15 10:43 的评论:
我给出一个终极结论:
(1)数学是最可靠的科学,是所有科学的基础,不容否定,有些学科对数学的依赖很重,有些学科依赖较轻,编程有时对数学依赖很重,那要看你在编写什么程序。
(2)数学出现问题,不是学科本质的问题,而是符号系统的问题,也就是表现形式的问题,所以否定的对象一定要搞清楚。
(3)数学家有其自己的思维方式,你不能要求别人和你一样思维,你干程序,大部分时间并没有像数学家那样思维。
(4)一个艺术家很少抱怨数学,因为艺术不需要数学,或者说很少需要数学,你在抱怨数学,说明什么?说明你的程序员工作,和数学
来自甘肃白银的 Chrome 31.0|Windows 7 用户 2015-12-15 10:46 11 回复
不要否定别人,来提升自己。
不要自己不会,就说它不好。
来自甘肃白银的 Chrome 31.0|Windows 7 用户 2015-12-15 10:30 8 回复
文中观点,我个人只支持相当大的一部分,

文中提到,数学符号系统的瑕疵,确实存在,所有已知数学知识,都很简单,但是数学是最纯粹的科学,是最可靠的结论,是所有科学的基础,不能否定数学。

我从来没有认为x^2是函数。
来自上海的 Firefox 11.0|Ubuntu 用户 2015-12-15 09:21 7 回复
其实你说的都是偏见,那个数学家不是严谨的,谁会说x^2是函数,这样扭曲事实是不对的,应该客观的分析,不应该这样
来自江苏淮安的 Firefox 42.0|Windows 7 用户 2015-12-12 17:09 8 回复
2020年,王垠承认当年说数学的书写不严谨是比较偏激的,“现在我并不是用C语言写东西,也不是用数学,而是用中文”。
[1]
来自广西柳州的 Sina Weibo 5.4|Android 4.4 用户 发表于 2015-12-11 20:39 的评论:
不会数学的人不知道数学的美。每一种学科玩好了就是艺术,玩砸了就是累赘,只能说王垠对数学以及数学在科研中的关键性知道的太少了
来自北京的 Safari 8.0|Mac 10.10 用户 2015-12-12 13:24 4 回复
“不会数学的人不知道数学的美”这点我反对,因为说得好像王某数学很差,好歹人家能考上211重点的四川大学,分数不会太低,How about you?
另外,我也要来一句:没学过单片机的孩子不知道机器的美。
计算机的本质是机器,它实际上的原理是物理开关,只是[借鉴数学,去实现更高效的逻辑处理]而已。
所以,数学不好的人,依然能写出[算法](处理问题的办法),就好比三杯酒的数学题,非得一定要用数学这门学科去解决?
这篇文章本来意图在于分清计算机科学与数学学科的区别,任何学科之间可以有关联互补互利之处,我记得大学有一堂高数
来自河北的 Firefox 42.0|Windows 8.1 用户 2015-12-12 09:44 6 回复
看了前面的几个人,我想问一句,你们上大学之前学编程了吗?你们学微积分之前会编程吗?
[1]
miradil [Firefox 42.0|Windows 7] 发表于 2015-12-10 16:13 的评论:
数学语言的编译器是能创造无限可能的人,程序代码的编译器是只会通电断电的电路板。
来自河北的 Firefox 42.0|Windows 8.1 用户 2015-12-12 09:42 8 回复
那直接用人去算不就好了,为啥还要发明计算机?
来自上海的 Sogou Explorer 2|Windows XP 用户 2015-12-11 19:15 15 回复
不知道前面几位的是怎么阅读的,王垠批评的只是数学的糟糕的“传统做法”,以及人们在这一方面的不思进取,并不是在批评数学的思想。数学作为一个悠久的学科,糟粕与精华并存本来就是正常的。不过另外一点,这篇文章也只是批评了数学的语法等等不如计算机学科,并没有对数学对计算机学科的作用和助力表达清楚。只是讲述了标题“数学与编程"的一个比较特别的方面而已。
[1]
POCMON [Firefox 42.0|Ubuntu] 发表于 2015-12-10 15:12 的评论:
听过一个故事:
一天聪明的牛顿在苹果树下玩,突然一个苹果掉下来来砸到脑袋了。
脑袋里闪现一个公式:F=GMm/R^2,牛顿心里记下了公式。
后来,牛顿开始思考为什么苹果会掉下来,而不是飞上天呢?
嗯,一定是因为地球引力,我要证明它。就用那个闪现出来的公式F=GMm/R^2吧,牛顿决定。
他把这个公式告诉了,数学家。于是数学家就开始研究F,代表什么,G代表什么等等。
只差最后一步时,数学家们实在没有办法了,总搞不定G,怎么办?
没办法,把G定义为一个常量吧,让其它“好变”的数去"变“吧。
至此,F=GMm/R^2公式的研究工作结束,向全世界公布!
linux [Chrome 46.0|Mac 10.11] 2015-12-11 18:17 4 回复
这故事真是故事。。。
来自北京的 UC Browser 10.8|Android 4.4 用户 2015-12-10 23:19 6 回复
优秀的程序员等于计算机科学家?
西风冷香 [Firefox 42.0|GNU/Linux] 2015-12-10 21:17 8 回复
作者理所当然地把程序语言的思想套在了数学语言上面,和他批评的那些把数学语言的思想套在程序语言上的人其实本质上没有什么区别。不同的是那些人有条件付诸实践,而他没有,不过是五十步笑百步罢了。
来自广东深圳的 Chrome 45.0|Windows 8.1 用户 2015-12-10 15:57 15 回复
不喜欢数学,就不要贬数学来提升计算机
来自湖南长沙的 Firefox 42.0|Windows 7 用户 2015-12-10 11:58 29 回复
王垠是一个很聪明的人,但不是一个有智慧的人。

返回顶部

分享到微信

打开微信,点击顶部的“╋”,
使用“扫一扫”将网页分享至微信。