艾达·洛芙莱斯在她关于分析机的笔记中描述了一个可重复的算法。看看她的早期思想如何映射到现代程序设计与计算思维上。

你大概听过那种简短版本:艾达·洛芙莱斯写出了“首个算法”,那是一组为查尔斯·巴贝奇的分析机设计的指令。人们至今引用它,因为这是一个早期且出乎意料地清晰的示例,展示了我们现在所说的编程——把一个目标拆成机器能遵循的精确步骤。
本文并不是要重建分析机的齿轮或试图解决每一个历史争议。相反,它聚焦于洛芙莱斯作品中的编程思想:如何把数学问题变成可执行的东西,如何表示数据,以及如何把一个过程写清楚,使其他人(或其他东西)能够运行它。
洛芙莱斯著名的“笔记”读来像数学与软件设计之间的一座桥。尽管那台机器在他们生前并未完成,但那种思考对任何曾试图让计算机做可靠工作的开发者都很熟悉。
我们接下来会关注的要点包括:
结束时的目标很简单:把洛芙莱斯的“首个算法”看得不只是博物馆里的展品,而是一种早期的计算思维模板,仍然映射到我们今天设计程序的方式。
奥古斯塔·艾达·金(艾达·洛芙莱斯伯爵夫人)在诗意与数学的交汇处成长。她的母亲鼓励严谨学习,艾达很快进入一小圈杰出的科学家与思想家中。她并不是孤立工作的天才,而是一位善于协作、善于提出特别清晰问题的人,她关心的是机器能“意味着什么”,而不仅仅是它们能“做什么”。
查尔斯·巴贝奇在设计机械计算方面已颇有名声。巴贝奇能在脑中设计硬件:齿轮、轴与数字轮组成的系统。与此同时,艾达善于解释——把复杂的技术思想翻译成结构化、可传达的概念。
他们的合作有效是因为各自强项不同。巴贝奇推动工程愿景向前;艾达推动概念愿景,尤其是强调机器可以按事先设计的操作序列来执行任务这一观念。
巴贝奇的分析机不仅仅是更好的计算器。纸面上它被描述为一台通用机器:可以存储数值、执行运算,并按计划逐步运行程序。把它想象成今天所说的可编程计算机的早期蓝图——尽管在他们有生之年并未建成。
19世纪40年代正是数学、工业与自动化开始交汇的时期。人们渴望可靠的方法——表格、公式与可重复的过程——因为错误代价高昂、科学发展迅速。在这种背景下,艾达对“如何指示一台机器”感兴趣并非一时之好奇,而是回应一个增长的需求:把人类的推理变成可重复、可检验的过程。
在洛芙莱斯描述算法之前,必须有一台值得“编程”的机器。巴贝奇的分析机被设想为一台通用计算器:不是为某一公式而建,而是可设置为执行许多不同的操作序列。
核心思想很直白:如果你能把问题拆成小的算术步骤(加、减、乘、除),那么机器应该能够可靠地按正确顺序执行这些步骤,且可重复执行多次。
这就是从一次性计算到可复用方法的跨越。
巴贝奇描述了两个主要部件:
对于输入和输出,分析机设计上采用穿孔卡(受织机启发)来输入指令与数据,并以人可用的形式产出结果——例如打印或记录。
若把这些概念映射到今天:
这就是分析机的重要性:它勾画出我们仍然依赖的分离——能执行步骤的硬件与定义执行哪些步骤的程序。
当人们谈论艾达·洛芙莱斯与首个算法时,常常指向她附在路易吉·梅纳布雷亚(Luigi Menabrea)关于巴贝奇分析机的意大利文论文译文上的一组“笔记”。
梅纳布雷亚描述了机器的概念,洛芙莱斯更进一步:她把分析机当作可以被指示的对象,而不是仅供欣赏的发明。这一转变正是这些笔记在编程史上如此重要的原因。它们读起来像早期的计算思维:把目标拆成精确步骤、选择表示法、预见机制如何去执行这些步骤。
洛芙莱斯的笔记解释了我们今天称为程序设计的内容。她以如何把操作序列化与控制化来描述分析机的各部分(比如储存与“加工器”)。核心观念简单但深刻:如果分析机可以按定义顺序对已定义的符号执行操作,那么“如何做”必须以机器能执行的形式写下来。
这就是她的工作开始与现代编程相似的地方:它不仅是理论,而是方法。
最重要的是,笔记中包含了一个以表格呈现的实例。它逐行列出机器应该做什么——哪些位置上有哪个值,下一步执行什么运算,结果放在哪里。
这种表格格式是当今伪代码、流程图和指令计划的祖先:一个明确且可检验的计划,你可以照着执行而不用猜测。无论你是否真的去构建分析机,这种习惯——把想法变成可执行序列——仍是编写软件的核心。
在日常语言里,算法是一个可重复的方法:一套清晰的步骤,可靠地把你从起点带到答案。它像一份不会依赖直觉的食谱——按步骤做,你每次都应得到相同结果。
艾达著名的示例算法旨在计算伯努利数——这是一列在数学多个领域出现的数值(例如某些求和公式与微积分部分)。你不需要理解它们的全部理论背景,就能体会它们为何是考察早期计算机器的好“试金石”。
它们在恰当的意义上具有挑战性:
换句话说,它足够复杂以证明机器能遵循结构化方法,但又够有序可以被逐步写下。
从核心上看,算法具有我们在程序中仍然使用的熟悉结构:
这样看,洛芙莱斯不仅仅展示了一个数字如何计算——她展示了如何组织一个多步计算,使机器能在不猜测的情况下执行。
当人们谈论洛芙莱斯的伯努利数算法时,常把注意力放在结果上(“一个早期程序”),而不是使步骤可靠的设计工作。真正的成就并非仅列出运算——而是把运算塑造成机器能无须即兴发挥地遵循。
笔记不是把“计算伯努利数”当成一项整体任务,而是把它分成可重复且可检查的小任务:计算中间值、按特定公式组合它们、记录结果,然后进行下一轮。
这种分解重要,因为每个子任务都能单独验证。如果输出看起来错了,你不会去调试“整个算法”;而是检查某一部分。
机械计算机不会“记在脑里”。任何稍后需要的值都必须被存放到某处,笔记在这方面很谨慎。有些数字是临时工作值;有些是必须为后续步骤保留的最终结果。
这是一种早期的程序状态思考:
操作顺序本身就是一种安全手段。某些计算必须先于其它计算完成,不是为了优雅,而是为了避免使用尚未准备好的值或无意中覆写仍需使用的值。
用现代术语说,洛芙莱斯在设计控制流,使程序有一条清晰路径:先做 A,再做 B,然后做 C——因为先做 B 会暗中导致错误答案。
在洛芙莱斯的步骤表里隐藏着一个最“现代”的观点:重复——按相同的一组指令反复执行,不是因为无计可施,而是因为重复是达到结果的最快路径。
程序中的重复意味着:执行一小段步骤,检查是否完成;若未完成,则再次执行同一段步骤。关键在于每次执行时某些东西发生变化——常见的是计数器、表中的位置或你正在累积的值——于是程序向终点前进。
在洛芙莱斯的记法中,你可以把它看作结构化地返回到早先的步骤。她不是把相同的指令写 N 遍,而是描述了一个模式并指明何时循环回去。这正是我们现在称为迭代的萌芽。
如果你写过代码,你会在 for 循环(“重复 N 次”)或 while 循环(“直到某条件成立时停止”)里见到相同模式。她的表格也隐含了现代循环所需的要素:
想象你要计算 1 到 5 的和。
total = 0 开始i = 1 开始i 加到 total 上i 增加 1i 仍小于或等于 5,就重复加与增加的步骤这就是通俗的迭代:一个小循环更新计数器并累积结果。洛芙莱斯的贡献不仅在于她计算了什么,而在于她展示了重复结构可以被清楚地写下来,足以让机器(和未来的人)可靠地执行。
一个过程在你脑中可能完全合乎逻辑,但没有一种指称变化量的方式,对机器或他人来说却可能无法执行。这就是变量和符号的重要性所在。
把变量想成桌上的带标签的盒子。标签不变,但里面的内容会在工作中变化。
若你在计算一个序列,可能会有:
没有这些盒子,你就得用长句子描述(“取两步前计算出的数值……”),很快就会变得混乱。
在洛芙莱斯的笔记中,符号与标签并非形式主义,它们是为了使过程可执行而存在。清晰的符号回答了实务问题:
当过程变长时,这些小小的澄清可以防止最常见的错误:把相似的量混淆。
良好的变量命名仍是减少错误的廉价方法。比较 x1、x2、x3 与 current_sum、term_index、next_term:后一组能告诉你这些盒子的用途。
类型再加一层安全性。决定某个值是整数、浮点、列表还是记录,就像选择合适的容器——某些错误因此变得不可能或至少更容易提前发现。
变量与符号把“聪明的想法”变成任何人(包括机器)都能正确重复的步骤。
抽象意味着关注重要的事并有意隐藏不重要的细节。这是“对这个列表排序”与逐一描述每次比较与交换之间的区别。洛芙莱斯的笔记早早表现出这种倾向:她试图把方法表达清楚,而不把读者困在机器的机械细节中。
笔记的一个显著特点是,它把核心方法与机器的物理动作区分开来。分析机有自己的“如何做”(齿轮、储存、加工),但笔记强调的是“做什么”:达到结果所需的操作序列。
这种分离是我们今天称为软件设计的萌芽:
当你可以在不再反复解释机器细节的情况下描述方法时,你已经在把计算视为可移植的东西——可以在不同硬件或由不同人重新实现。
笔记中的逐步表类似于早期的“过程”:一套定义好的步骤,可以多次执行。现代代码把它规范化为函数、模块与可重用组件。
一个好的函数像洛芙莱斯的表达那样:
因此抽象并非模糊,而是可用。表达清晰的方法自然带来重用:你可以在新场景中调用它,与其它方法组合,构建更大的系统而不被细节淹没。
艾达·洛芙莱斯不仅描述了分析机能做什么——她示范了如何把一个过程写得无歧义,便于他人(或机器)遵循。她笔记的静默力量在于:解释就是工作的一部分,而非装饰。
她的呈现之所以现代,是因为使用了结构化的逐步表。表格会强迫做出决定,而模糊的散文可能掩盖这些决定:
这会减少歧义,就像今天的伪代码一样。你可以读一段段落然后以为懂了,直到你尝试去执行它。步骤表能把“执行路径”呈现出来,这正是良好程序文档所追求的。
洛芙莱斯的笔记集合了三样我们今天仍试图保持在一起的东西:
程序的目的(意图)
它如何工作(过程)
如何解释符号(接口:命名、符号、假设)
这与现代的注释、文档字符串和 README 很契合。README 解释目标与背景。内联注释澄清难点。文档字符串定义输入/输出和极端情况。当任何一项缺失时,使用者就只能猜测,而猜测正是错误的温床。
当你为一个过程(无论是否代码)写文档时,按以下方式写,假设有人会在没你在场的情况下复现它:
这些不是额外工作——这是把方法变得可复用的方式。
艾达常被冠以“第一位程序员”的响亮称号。这是个有用的简写,但也可能抹平更有趣的事实。争论不仅关乎名誉,更关乎我们如何定义“程序”“计算机”和“作者权”。
如果把“程序员”理解为为通用机器写下指令的人,洛芙莱斯有很强的理由被认为符合条件。她在分析机的笔记中描述了生成伯努利数的逐步方法——本质上是让分析机执行非平凡计算的计划。
但历史学家争论此称号的原因包括:
把“发明计算思想”与“制造一台可工作的计算机”区分开很重要。巴贝奇的主要贡献是架构:提出一个有储存(“store”)、处理器(“mill”)和通过穿孔卡控制的机器。洛芙莱斯的贡献则是解释性与表达性的:她阐明了这类机器可以代表什么,以及如何把一个过程写下来使机器能够执行。
一个程序并不会因为硬件当时不存在而不再是程序。从现代角度看,这就像为尚处于理论阶段的平台写软件,或在芯片还不存在时先指定算法。
尊重地谈论这个时代的一种方式是把它看作跨角色的协作:
我们可以自信地说:洛芙莱斯的笔记帮助定义了什么是编程——不仅仅是计算,还是把过程以机器可遵循的无歧义形式表达出来。
洛芙莱斯的笔记之所以重要,是因为它们展示了在把想法变成机器可执行计划时应如何思考。即便你从不接触穿孔卡或机械齿轮,核心教训仍能映射到现代程序设计:给工作明确的结构、仔细命名、把重复作为工具,并构建可复用的组件。
结构胜过聪明。 当程序被拆成有明确目的的步骤时,构建与维护都更容易。洛芙莱斯的方法鼓励你在纠结细节之前先设计解决方案的形状。
清晰即特性。 她的表格与解释不是装饰——它们是程序的一部分。当将来的你(或队友)能快速跟上逻辑,程序就更可靠。
迭代是工具,不是技巧。 重复(循环)是扩展方法的手段。关键是定义重复的内容、每次变化的部分以及何时停止。
抽象促成重用。 如果一系列步骤能工作一次,你应该能用不同输入再次使用它。这是函数、模块与库的萌芽。
如果你曾用“通过描述来构建”的工作流——先写需求、迭代计划,然后生成可工作的软件——你已经在重演洛芙莱斯笔记的精神:把过程明确、保持状态清晰、并记录假设以实现可重复执行。这也是像 Koder.ai 这样的工具自然而然融入这一故事的原因。Koder.ai 让你通过聊天界面创建网页、后端与移动应用,但相同的基本原则仍适用:在你生成或修改代码前,用规划模式把“笔记”固定下来,明确输入/输出并保持命名一致,会得到更好的结果。
在开始编码前或在调试感觉混乱的问题时,做一次快速检查:
如果你想强化“先做笔记再编码”的程序设计风格,这些会有帮助:
把这些习惯结合起来,会把编程从“让它能跑”变成“让它可理解”——这正是洛芙莱斯的笔记早已指向的转变。
艾达·洛芙莱斯的“首个算法”是她在《笔记》中呈现的一套逐步指令,意在由查尔斯·巴贝奇的分析机执行。它著名的原因在于:它将计算视为对存储值进行按序操作的有计划步骤,这与现代编程非常相似,尽管当时那台机器并未完工。
本文侧重于洛芙莱斯作品中的编程思想:如何把方法表达为可执行、可检验且易于理解的步骤——而不是试图还原分析机的硬件结构或解决所有历史上的争议。
分析机是一个被设想的通用机器,旨在:
这个架构重要的地方在于它把执行步骤的硬件与规定要执行哪些步骤的程序分离开来——这正是现代计算机所依赖的基本分工。
伯努利数在多处数学公式中出现。它们是一个很好的示例问题,因为每一个新值都依赖先前的值,需要多次运算、中间存储和可重复的步骤——正是用可编程机器测试结构化计算能力时需要的条件。
步表会强制精确化。它要求你明确说明:
这就是它与现代伪代码相像的原因:让别人能够在不猜测的情况下“运行”这个过程。
重复是迭代的早期形式:定义一小套步骤,每次执行改变某些内容(例如计数器或部分结果),并在满足条件时停止。在现代代码中,这对应于 for / while 循环,构件包括:
因为机器不能像人一样靠上下文“记住”事情。变量式的标记能让你跟踪:
这些标记能显著减少长过程里最常见的错误:把相似的量搞混。
抽象就是聚焦重要的部分并有意隐藏那些不重要的细节。洛芙莱斯的《笔记》把方法与机械细节区分开来:
把方法表达清楚后,我们就可以像用函数或模块那样重复使用它:命名、接收输入、产生输出,并在不需要时隐藏内部步骤。
这个称号有争议,因为:
更稳妥的说法是:洛芙莱斯的《笔记》明确界定了什么是编程——不仅仅是计算,而是把一个过程以无歧义的方式写出来,让机器能够跟随。
在把想法变成机器可执行的计划时,洛芙莱斯的《笔记》给我们不少实用启示。即便你不接触穿孔卡或机械齿轮,核心教训仍然适用于现代程序设计:
相关阅读: 和 。