迭代版本:39,约5.5千字
数学思维与**编程思维——都包括了抽象与逻辑**,但它们之间有何不同?
本文将会,在概念上一探究竟,在内涵上详细解读,直至银弹与永恒。
主题目录如下:
- 不同的抽象
- 逻辑交叉点
- 函数的抽象
- 数学与编程
- 抽象与封装
- 演化与银弹
- 短暂与永恒
- 算法与比特
- 结语
不同的抽象
首先,数学思维的抽象,在于剥离具体。
数学与具体现实完全脱离,其人为的**“定义”与“构造”,就是为了隔离现实获得抽象**,然后以此为基础,推理证明出更多抽象,如此反复,最终得到的全是无关现实。
数学的抽象,只需要**逻辑自洽的结构与关系,其目标与结果,是在构建一个纯逻辑编织的“抽象世界”**。
其次,编程思维的抽象,在于映射具体。
编程是用来,模拟现实运作并解决实际问题的(包括满足精神需求)——因此,编程与现实极为紧密,而现实世界极其错综复杂,所以代码无法避免冗余与意外,其映射现实的复杂度,必然会随机出不曾意料的排列组合,即涌现出不可避免的Bug。
这也就是为什么,数学的正确与错误清晰而明确,但编程就无法保证绝对正确与完美无错,而只能说目前没有发现问题——显然,现实情况发生变化了,编程映射的代码模型,就需要跟着一起变化,结果就是Bug永远存在,需要不断修复与不停更新。
例如,在**《计算机程序的构造和解释》**中,就曾指出:“每一个计算机程序,都是现实中的或者精神中的,某个过程的一个模型,通过人的头脑孵化出来。”
所以说,编程的核心是编程思想,即:要看清并能理解,事物之间的相互关联,以及交互的相互影响。
最后,这是两种不同目的的抽象,**数学思维**的抽象在于——寻找未知逻辑关系,编程思维的抽象在于——利用已知逻辑关系。
那么,这两种**抽象思维的共通之处,就是需要梳理逻辑关系**。
而两者最大的不同就在于,数学思维对现实世界的实际经历,要求不多也不高,但编程思维对现实世界的体验理解,必须实际且丰富。
也就是说,数学思维可以——脱离现实、独立存在、闭环运转,但编程思维则需要——从现实出发、经过抽象后、再回归现实。
逻辑交叉点
从某种角度来看,逻辑就是事物所固有的关系,即:逻辑是顺着结构所看到的关系——如果理解了关系的相互作用,就是掌握了结构的运作规律。
为什么按照逻辑,应该是这样的?为什么这个逻辑是对的?为什么那个逻辑就是错的?原因就在于,逻辑的本质是客观结构所呈现的客观关系。
那么,正确的逻辑——就是可以客观存在的结构关系,错误的逻辑——就是无法客观存在的结构关系。
于是逻辑推理,就是根据经验、直觉与理性,结合逻辑规律(即符合同一律、矛盾律、排中律、无矛盾),对结构可能存在的关系,进行预测并验证——正确即有逻辑、错误即无逻辑。
但注意,不同的角度看相同的结构,可能会有不同的关系,即有不同的逻辑——当然,相同的角度看不同的结构,也可能会有相同的关系,即有相同的逻辑,如:在演化角度下,具有相同的底层逻辑,就依赖于此。
这就是有趣的地方,数学研究的是结构与关系,而现实世界就可以抽象成结构与关系,并且是正在实际运行的结构与关系。
因此,数学在人脑里自由探索的结构与关系,必然会与现实世界产生交集,而这个**“交集”就是编程用来解决现实问题的“工具”**。
当然,现实世界会有超出已知数学但急需解决的编程问题,这就只能另辟蹊径,使用模拟、近似、穷举、迭代、演化等启发式方法,来计算出一个实际中可行可用的有效解。
但无论如何,逻辑关系依附于结构之上,在抽象视角下,相同的结构,就会有**“通用的逻辑”——这是现实世界、数学世界、编程世界的“逻辑交叉点”**。
最后,宇宙结构、人脑结构、数学结构、代码结构……结构无处不在,关系无处不在——逻辑就是通向所有结构与关系的连接与指引。
函数的抽象
函数,是一个量到另一个量的计算,计算就是处理关系的演化——所以,函数的构建过程,其实就是结构的关系,通过逻辑被模拟映射的过程。
函数可大可小,小到一次映射,大到整个宇宙——甚至说,函数,塞得下你的人生,存得了你的记忆,藏得住你的闪念,算得完你的想要。
因此,数学与编程,都会利用函数来抽象建模,即:函数就是连接数学与编程的抽象。
需要指出的是,编程中的函数可以没有输入值或**返回值(或都没有)——此时函数就不是输入映射到输出**,而是上下文中的某个值映射到另个值,或某个值映射到某界面、某位置、某设备等等。
但从某种角度来说,编程更接近物理而不是数学,因为编程与物理都是探究现实世界的运作,而在现实世界,基于程序的编程发现,也将会逐渐取代基于方程的数学发现。
数学与编程
在很多层面,数学与编程都有共通之处,就如:
- 数学实现与编程实现,都在于思想与技巧。
- 数学语言与编程语言,都依赖于符号系统。
- 数学变量与编程变量,都承载了逻辑运行。
- 数学构造与编程构造,都是工具封装重用。
- 数学错误与编程错误,都会摧毁所有构建。
事实上,数学与编程的运作过程,也是十分相似的,都在于方向与细节(即构建结构与使用结构),以及对结构内在关系的探索与服从(即排列组合结构与逻辑推理关系)——并且从中都可以获得,构造结构的乐趣。
那么,两者的不同之处,就在于:
- 数学——处理的是说明式的知识,即是什么的知识。
- 编程——处理的是命令式的知识,即怎么做的知识。
而一个有关**“是什么”的知识,可被用于解决不同的问题,其中包含着不同的“怎么做”的部分,即:数学可以作为编程**的工具。
相反,编程也可以通过**演化计算,以非人脑的方式去发现数学,即:编程成为人脑探索数学**的工具。
总之,“利用自身的规则去构建自己的世界”——这是数学与编程所共有的特性。
抽象与封装
抽象,是以简化形式来忽略细节。封装,是以简化形式来屏蔽细节。抽象封装,可以通过压缩复杂细节,来实现管理复杂度。
而抽象封装的作用重大,它可以——建模现实世界、降低使用难度、隔离内部错误、限制变动影响、隐藏实现细节、无缝更新升级、简化交互过程、集中管理控制、易于功能重用。
例如,在编程领域,“抽象屏障”——能够隔离数据与算法、表示与使用、界面与逻辑、高层操作与底层结构,甚至还能隔离设计选择,从而让不同的设计选择,可以在同一个程序里共存。
在表达思想层面,抽象是一种化繁为简的设计——它将微观以宏观的形式展现,让人可以同时**“从远看近”与“从近看远”,远看清整体,近看清局部,两者结合是对事物最精准**的把握。
事实上,认识是从具体到抽象,控制是从抽象到具体,从认识到控制的中心环节,就是运用抽象封装——这是我们理解世界与安身立命的思维根基。
那么,如果一个设计,需要看到内部实现与底层原理,方能理解与使用,就是失败的抽象——可以说,破坏抽象封装的表现,就是内部的具体细节,被外部获取与依赖。
在体验层面,抽象封装的意义还在于,充当逻辑世界与精神世界的桥梁,从而让人获得**“秩序感”**。
最后,“除非必要,务增难度”——就是编程领域的“奥卡姆剃刀”,即可以称之为**“抽象剃刀”**。
演化与银弹
面向对象编程,把数据与行为打包,其实是符合演化模型的——演化可以容忍冗余,并利用冗余变得强大。
那么,把行为拆出来给系统,对象就无法演化了,即变成系统演化,数据只是数据。因为这里存在一个更深层次的视角,就是数据与结构可以相互转化。而在更独立内聚的层面,像容器数据结构,还是要以面向对象编程的形式存在与使用。
如果只是为了缓存友好,就拆出一个行为系统,但这个模型又无法从上到下,贯彻统一到最底层,不免就破坏了层级封装,即程序层面不考虑硬件特性——这是一种耦合。
所以,未来会演化出一个**“层级”,来屏蔽缓存友好**的问题。
从某种角度来说,面向对象编程是具有分形递归特性的——大自然也没有使用**“多继承”,这里应该存在一个终极的演化模型**,但前提是绝不能破坏层级封装,否则就无法正确模拟宇宙。
事实上,大脑的神经网络,充满了高冗余与**高内聚,大脑之间可以通过“各种连接”,来交换数据与信息,而缓存友好的问题,是通过“数据与结构一体化”的神经模型解决的——顺着这个模式视角,就可以构造出一个终极的“通用程序模型”**。
显然,大脑的算力是很弱的,通过进行心算就会发现这一点,并且这个算力还属于**流体智力,即会随着衰老不断下降——但大脑胜在,基于动态性支撑的通用智能**,而动态性需要冗余性。
值得指出的是,抽象会丢失信息,但会带来信息的联想关联,因为减少冗余,可以更容易连之难连(尤其是遥远的信息之间),而冗余中则潜藏着,各式各样有用的排列组合。
那么,抽象层级就是编程与程序,得以有效运转的重要基石,而穿越抽象层级的连接、协调与调用,就是一种耦合——跨硬件、跨设备、跨平台、跨接口,才是我们想要的,也是一种**“通用模型”**。
因此,程序架构会使用抽象层级,来屏蔽外部环境的差异性——如果抽象层级足够通用,具有很好的适应性,程序架构就可以与环境实现解耦。
但如果,程序架构为硬件定制,这种强耦合就会失去,通用的演化能力——之所以,有时候要去适应硬件设计,如缓存友好与多线程等,可能有两方面的原因:一是想要极端极致的压榨速度,二是没有足够好的抽象层级。
我们可以看到,随着硬件性能的不断提升,编程语言越来越动态化,越来越远离硬件,这是编程模型的演化趋势。
显然,大脑具有**“软硬件一体”的动态性,但计算设备无法具有这种动态性**,于是就把这个动态性转移给了程序算法——因此有时会要求,软件编程来适应硬件特性,这是一种软硬耦合,通常是为了获得运行速度。
站在演化角度,宇宙不在乎时间,也不在乎速度——我们在乎时间与速度,是因为我们个体的时间有限。但无论是基因信息的演化,还是模因信息的演化,几乎是没有时间限制的永续迭代,这是信息演化的特性,所以信息演化对速度的敏感度与追求度,是很低的——而用无限的时间,就可以演化出终极的**“通用模型”**。
事实上,人脑架构的强大之处,就在于可以动态地创造算法——对编程语言来说,数据结构与算法可以相互转化,就是数据结构越简单算法就需要越复杂,数据结构越复杂算法就可以越简单,于是就可以用数据结构来等价创造算法,而有效地利用这一点,就可以让程序架构类似人脑架构,实现动态地创造算法,而这就是一种**“通用演化模型”**。
试想,如果大脑架构不通用,每一种环境都需要定制一个大脑架构,并且还经常淘汰各种大脑架构,那么人类智能也就不会是现在这样子了。
所以,通用架构的演化模型是存在的,关键在于——动态性(需要冗余性)与抽象层(屏蔽冗余性)。
类比来看,大脑的神经网络,具有极其高内聚与低耦合的特性——高内聚体现在,其功能实现不依赖**“颅外调用”;低耦合体现在,其功能扩展只需要“颅内传参”**。
这就像说,通过程序的**“接口交互”,就可以实现程序功能的增强、扩展与改变——这简直就是,程序设计的“银弹架构”,其具有完美的动态性与适应性**。
而就追求速度来看,宇宙是有光速限制的,所以程序的运行速度,是必然存在上限的——但这一点,可以通过**“无限的空间”**来解决或绕过。
最后,人类智能与机器智能,可以模拟同态性(即结构相似存在不对应),甚至实现同构性(即结构相同逻辑性一致)——这需要建立在,**“通用银弹架构”的“演化程序模型”**之上。
短暂与永恒
和短暂对话,就会获得短暂,和永恒对话,就会获得永恒。
短暂就是表面、特例、具体、当下,永恒就是根本、普遍、抽象、长远——我们思维对话的**“问题对象”,决定了我们思考的结果,将会是短暂还是永恒**。
我们身处某个时代,必然会被这个时代的前沿科技所局限,但可以通过和**“永恒的事物”对话,从而超越我们自己的时代,即搭上“永恒的机器”**,穿梭于所有时代。
所以,一个人的思考与创造,可以不属于他眼前的时代,就在于持有永恒的演化思维,并将其注入排列组合的迭代过程。
事实上,那些能把更本质的问题,想得**“透彻自洽”的人,宇宙定会给予他“深度参与”的机会,因为宇宙喜欢能“理解映射”**祂的人。
算法与比特
算法,就是**“看待结构”的角度与“操控结构”的方式,其核心是正确处理“结构关系”**。
结构,是事物固有的存在;关系,是观察结构的结果;相同的结构,不同的角度,会看到不同的关系,而有些(甚至绝大部分)关系,则是观察者所无法感知、理解与处理的。
因此,有时候换个角度看问题,就会恍然大悟,就会豁然开朗,就会迎刃而解,也会得到全新的答案——就是因为不同的角度,可以获得有关结构的更多关系。
相反,如果看待结构的角度不对,那么数据正确、分析正确、逻辑正确、处理正确,但结果依然不会正确——因为关系不匹配。
有趣的是,比特是信息的基本单位,结构与关系需要用信息去描述,于是计算机系统通过比特信息,就建立起了与万物的映射关系。
所谓,万物皆比特,宇宙是计算——前者是程序,后者是编程,连接程序与编程的就是算法。
结语
从某种角度来说,编程 = 数学 + 物理 + 抽象——其中,数学决定了效率,物理决定了效用,抽象决定了模型,而一个有效率、有效用的模型,则决定了程序的价值。
那么对于编程,应用数学与物理是确定的——因为只需要当工具使用已知的部分,应用抽象则是不确定的——因为与现实世界相关且充满未知的部分。
事实上,编程正在向物理收敛,物理正在向数学收敛,即:编程模拟物理世界,物理走向数学世界。
而最终,我们将生活在,计算机编程的虚拟世界:第一步计算机成为我们的延伸,第二步我们本身成为计算机——这是两种神经网络的融合,也是从人类智能到机器智能的演化。
但无论如何,就如**《计算机程序的构造和解释》**中,所言:
“如果说艺术,解释了我们的梦想,那么计算机就以程序的名义,执行着它们。发明并调整,调整恰当之后再发明,让我们祝福那些,把思想和逻辑,镶嵌在重重字符之间的程序员们。 ”
最后,编程的最高境界,也是编程的彻底终结——这一切都是从程序执行了你没写的代码开始的。
主题相关文章: