1 分钟

艾达·洛芙莱斯的首个算法及其对今日的启示

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

艾达·洛芙莱斯的首个算法及其对今日的启示

这则故事真正关乎什么

你大概听过那种简短版本:艾达·洛芙莱斯写出了“首个算法”,那是一组为查尔斯·巴贝奇的分析机设计的指令。人们至今引用它,因为这是一个早期且出乎意料地清晰的示例,展示了我们现在所说的编程——把一个目标拆成机器能遵循的精确步骤。

本文并不是要重建分析机的齿轮或试图解决每一个历史争议。相反,它聚焦于洛芙莱斯作品中的编程思想:如何把数学问题变成可执行的东西,如何表示数据,以及如何把一个过程写清楚,使其他人(或其他东西)能够运行它。

为什么它仍然重要

洛芙莱斯著名的“笔记”读来像数学与软件设计之间的一座桥。尽管那台机器在他们生前并未完成,但那种思考对任何曾试图让计算机做可靠工作的开发者都很熟悉。

我们接下来会关注的要点包括:

  • 步骤与结构: 将工作拆成有序操作,而不是模糊的意图。
  • 数据与符号: 决定哪些值存在、如何命名、如何在过程中流动。
  • 重复: 识别模式并重用,而不是重复写相同动作。
  • 检验你的工作: 设计可以被验证的过程,而不仅仅是让人钦佩的描述。
  • 文档: 写出让他人能理解程序的解释。

结束时的目标很简单:把洛芙莱斯的“首个算法”看得不只是博物馆里的展品,而是一种早期的计算思维模板,仍然映射到我们今天设计程序的方式。

艾达·洛芙莱斯、巴贝奇与分析机

奥古斯塔·艾达·金(艾达·洛芙莱斯伯爵夫人)在诗意与数学的交汇处成长。她的母亲鼓励严谨学习,艾达很快进入一小圈杰出的科学家与思想家中。她并不是孤立工作的天才,而是一位善于协作、善于提出特别清晰问题的人,她关心的是机器能“意味着什么”,而不仅仅是它们能“做什么”。

艾达与巴贝奇如何相识

查尔斯·巴贝奇在设计机械计算方面已颇有名声。巴贝奇能在脑中设计硬件:齿轮、轴与数字轮组成的系统。与此同时,艾达善于解释——把复杂的技术思想翻译成结构化、可传达的概念。

他们的合作有效是因为各自强项不同。巴贝奇推动工程愿景向前;艾达推动概念愿景,尤其是强调机器可以按事先设计的操作序列来执行任务这一观念。

分析机在其中的地位

巴贝奇的分析机不仅仅是更好的计算器。纸面上它被描述为一台通用机器:可以存储数值、执行运算,并按计划逐步运行程序。把它想象成今天所说的可编程计算机的早期蓝图——尽管在他们有生之年并未建成。

为什么19世纪40年代重要

19世纪40年代正是数学、工业与自动化开始交汇的时期。人们渴望可靠的方法——表格、公式与可重复的过程——因为错误代价高昂、科学发展迅速。在这种背景下,艾达对“如何指示一台机器”感兴趣并非一时之好奇,而是回应一个增长的需求:把人类的推理变成可重复、可检验的过程。

对分析机的一个简明视角

在洛芙莱斯描述算法之前,必须有一台值得“编程”的机器。巴贝奇的分析机被设想为一台通用计算器:不是为某一公式而建,而是可设置为执行许多不同的操作序列。

它的基本目的

核心思想很直白:如果你能把问题拆成小的算术步骤(加、减、乘、除),那么机器应该能够可靠地按正确顺序执行这些步骤,且可重复执行多次。

这就是从一次性计算到可复用方法的跨越。

用通俗语言描述的部分:内存、运算、输入/输出

巴贝奇描述了两个主要部件:

  • “储存”(store,内存): 存放数字以便处理中途复用。可以把它想成你在做笔记时放中间结果的记事本。
  • “加工器”(mill,运算): 从储存中取出数值做运算,然后把结果放回去。这是算术发生的工作台。

对于输入和输出,分析机设计上采用穿孔卡(受织机启发)来输入指令与数据,并以人可用的形式产出结果——例如打印或记录。

一个有帮助的现代类比

若把这些概念映射到今天:

  • Mill ≈ CPU: 执行运算。
  • Store ≈ RAM: 存放当前处理的数据。
  • 卡片 ≈ 程序与数据文件: 告诉机器要做什么以及用什么数据做。

这就是分析机的重要性:它勾画出我们仍然依赖的分离——能执行步骤的硬件定义执行哪些步骤的程序

改变我们对机器认识的那些笔记

当人们谈论艾达·洛芙莱斯与首个算法时,常常指向她附在路易吉·梅纳布雷亚(Luigi Menabrea)关于巴贝奇分析机的意大利文论文译文上的一组“笔记”。

梅纳布雷亚描述了机器的概念,洛芙莱斯更进一步:她把分析机当作可以被指示的对象,而不是仅供欣赏的发明。这一转变正是这些笔记在编程史上如此重要的原因。它们读起来像早期的计算思维:把目标拆成精确步骤、选择表示法、预见机制如何去执行这些步骤。

不只是评论:如何写出可执行指令的手册

洛芙莱斯的笔记解释了我们今天称为程序设计的内容。她以如何把操作序列化与控制化来描述分析机的各部分(比如储存与“加工器”)。核心观念简单但深刻:如果分析机可以按定义顺序对已定义的符号执行操作,那么“如何做”必须以机器能执行的形式写下来。

这就是她的工作开始与现代编程相似的地方:它不仅是理论,而是方法。

让它具体的逐步表

最重要的是,笔记中包含了一个以表格呈现的实例。它逐行列出机器应该做什么——哪些位置上有哪个值,下一步执行什么运算,结果放在哪里。

这种表格格式是当今伪代码、流程图和指令计划的祖先:一个明确且可检验的计划,你可以照着执行而不用猜测。无论你是否真的去构建分析机,这种习惯——把想法变成可执行序列——仍是编写软件的核心。

伯努利数算法,简单解释

在日常语言里,算法是一个可重复的方法:一套清晰的步骤,可靠地把你从起点带到答案。它像一份不会依赖直觉的食谱——按步骤做,你每次都应得到相同结果。

艾达著名的示例算法旨在计算伯努利数——这是一列在数学多个领域出现的数值(例如某些求和公式与微积分部分)。你不需要理解它们的全部理论背景,就能体会它们为何是考察早期计算机器的好“试金石”。

为什么伯努利数是好例子

它们在恰当的意义上具有挑战性:

  • 每一个新的伯努利数依赖早先的值,不能只做一次快捷计算就结束。
  • 计算涉及多种运算(加、减、乘、除),不是单一技巧。
  • 有已知的正确序列,因此结果可以被验证。

换句话说,它足够复杂以证明机器能遵循结构化方法,但又够有序可以被逐步写下。

方法的形态:输入 → 工作值 → 结果

从核心上看,算法具有我们在程序中仍然使用的熟悉结构:

  • 输入: 固定常数与为计算下一项所需的先前伯努利数。
  • 中间值: 途中产生的临时结果——部分和、乘积与分数,需要保留以便复用。
  • 最终结果: 序列中的下一个伯努利数。

这样看,洛芙莱斯不仅仅展示了一个数字如何计算——她展示了如何组织一个多步计算,使机器能在不猜测的情况下执行。

分解与控制流:隐藏的设计工作

启动 Flutter MVP
将简单规格转成可快速测试的 Flutter 移动原型。

当人们谈论洛芙莱斯的伯努利数算法时,常把注意力放在结果上(“一个早期程序”),而不是使步骤可靠的设计工作。真正的成就并非仅列出运算——而是把运算塑造成机器能无须即兴发挥地遵循。

分解:把大目标拆成小职责

笔记不是把“计算伯努利数”当成一项整体任务,而是把它分成可重复且可检查的小任务:计算中间值、按特定公式组合它们、记录结果,然后进行下一轮。

这种分解重要,因为每个子任务都能单独验证。如果输出看起来错了,你不会去调试“整个算法”;而是检查某一部分。

状态与内存:必须记住什么

机械计算机不会“记在脑里”。任何稍后需要的值都必须被存放到某处,笔记在这方面很谨慎。有些数字是临时工作值;有些是必须为后续步骤保留的最终结果。

这是一种早期的程序状态思考:

  • 哪些值需要在下一阶段继续存在?
  • 哪些值可以安全覆写?
  • 哪些值应保持不变,因为后续步骤依赖它们?

控制流:通过顺序防止错误

操作顺序本身就是一种安全手段。某些计算必须先于其它计算完成,不是为了优雅,而是为了避免使用尚未准备好的值或无意中覆写仍需使用的值。

用现代术语说,洛芙莱斯在设计控制流,使程序有一条清晰路径:先做 A,再做 B,然后做 C——因为先做 B 会暗中导致错误答案。

循环、重复与迭代的概念

在洛芙莱斯的步骤表里隐藏着一个最“现代”的观点:重复——按相同的一组指令反复执行,不是因为无计可施,而是因为重复是达到结果的最快路径。

毫无神秘的重复

程序中的重复意味着:执行一小段步骤,检查是否完成;若未完成,则再次执行同一段步骤。关键在于每次执行时某些东西发生变化——常见的是计数器、表中的位置或你正在累积的值——于是程序向终点前进。

在洛芙莱斯的记法中,你可以把它看作结构化地返回到早先的步骤。她不是把相同的指令写 N 遍,而是描述了一个模式并指明何时循环回去。这正是我们现在称为迭代的萌芽。

她的步骤表如何映射到现代循环

如果你写过代码,你会在 for 循环(“重复 N 次”)或 while 循环(“直到某条件成立时停止”)里见到相同模式。她的表格也隐含了现代循环所需的要素:

  • 计数器(当前是第几次)
  • 变化的值(当前的部分结果)
  • 停止条件(计数到达终点时停止)

一个友好的例子:求和

想象你要计算 1 到 5 的和。

  • total = 0 开始
  • i = 1 开始
  • i 加到 total
  • i 增加 1
  • 如果 i 仍小于或等于 5,就重复加与增加的步骤

这就是通俗的迭代:一个小循环更新计数器并累积结果。洛芙莱斯的贡献不仅在于她计算了什么,而在于她展示了重复结构可以被清楚地写下来,足以让机器(和未来的人)可靠地执行。

变量与符号:把想法变成可执行的东西

从伪代码到产品
粘贴你的大纲,让 Koder.ai 将其转成真实代码和结构。

一个过程在你脑中可能完全合乎逻辑,但没有一种指称变化量的方式,对机器或他人来说却可能无法执行。这就是变量和符号的重要性所在。

变量如带标签的盒子

把变量想成桌上的带标签的盒子。标签不变,但里面的内容会在工作中变化。

若你在计算一个序列,可能会有:

  • 一个放当前结果的盒子
  • 一个放下一个输入值的盒子
  • 一个用于临时中间值的盒子,完成后可以丢弃

没有这些盒子,你就得用长句子描述(“取两步前计算出的数值……”),很快就会变得混乱。

符号不是装饰

在洛芙莱斯的笔记中,符号与标签并非形式主义,它们是为了使过程可执行而存在。清晰的符号回答了实务问题:

  • 现在哪个值在被更新?
  • 哪些值必须为后续步骤保留?
  • 哪些值是临时的可以被覆盖?

当过程变长时,这些小小的澄清可以防止最常见的错误:把相似的量混淆。

现代的回响:名字与类型

良好的变量命名仍是减少错误的廉价方法。比较 x1x2x3current_sumterm_indexnext_term:后一组能告诉你这些盒子的用途。

类型再加一层安全性。决定某个值是整数、浮点、列表还是记录,就像选择合适的容器——某些错误因此变得不可能或至少更容易提前发现。

变量与符号把“聪明的想法”变成任何人(包括机器)都能正确重复的步骤。

抽象与重用:从步骤表到函数

抽象意味着关注重要的事并有意隐藏不重要的细节。这是“对这个列表排序”与逐一描述每次比较与交换之间的区别。洛芙莱斯的笔记早早表现出这种倾向:她试图把方法表达清楚,而不把读者困在机器的机械细节中。

把方法与机制分离

笔记的一个显著特点是,它把核心方法与机器的物理动作区分开来。分析机有自己的“如何做”(齿轮、储存、加工),但笔记强调的是“做什么”:达到结果所需的操作序列。

这种分离是我们今天称为软件设计的萌芽:

  • 算法描述意图(例如计算伯努利数)。
  • 机器(或实现)处理执行细节(值放在哪里,如何运算)。

当你可以在不再反复解释机器细节的情况下描述方法时,你已经在把计算视为可移植的东西——可以在不同硬件或由不同人重新实现。

从步骤表到可重用的组件

笔记中的逐步表类似于早期的“过程”:一套定义好的步骤,可以多次执行。现代代码把它规范化为函数、模块与可重用组件。

一个好的函数像洛芙莱斯的表达那样:

  • 给操作命名,避免到处重复说明
  • 接受输入并产生输出
  • 隐藏内部步骤,除非你确实需要检查它们

因此抽象并非模糊,而是可用。表达清晰的方法自然带来重用:你可以在新场景中调用它,与其它方法组合,构建更大的系统而不被细节淹没。

文档是一项特性,而不是事后附加

艾达·洛芙莱斯不仅描述了分析机能做什么——她示范了如何把一个过程写得无歧义,便于他人(或机器)遵循。她笔记的静默力量在于:解释就是工作的一部分,而非装饰。

逐步表是“无法规避的伪代码”

她的呈现之所以现代,是因为使用了结构化的逐步表。表格会强迫做出决定,而模糊的散文可能掩盖这些决定:

  • 哪个先做、哪个后做
  • 每一步有哪些中间值存在
  • 何时更新值与何时仅引用值
  • 重复何处开始与结束

这会减少歧义,就像今天的伪代码一样。你可以读一段段落然后以为懂了,直到你尝试去执行它。步骤表能把“执行路径”呈现出来,这正是良好程序文档所追求的。

当时的笔记,今天的 README

洛芙莱斯的笔记集合了三样我们今天仍试图保持在一起的东西:

  1. 程序的目的(意图)

  2. 它如何工作(过程)

  3. 如何解释符号(接口:命名、符号、假设)

这与现代的注释、文档字符串和 README 很契合。README 解释目标与背景。内联注释澄清难点。文档字符串定义输入/输出和极端情况。当任何一项缺失时,使用者就只能猜测,而猜测正是错误的温床。

实用要点:把过程记录到别人能运行的程度

当你为一个过程(无论是否代码)写文档时,按以下方式写,假设有人会在没你在场的情况下复现它:

  • 陈述输入与输出(例如“给定 X,产生 Y”)。
  • 列出假设(单位、顺序、舍入规则)。
  • 用编号顺序或小表格写步骤
  • 给中间值命名并保持一致。
  • 包含一个可手算的小示例,让人可以核对结果。

这些不是额外工作——这是把方法变得可复用的方式。

神话、争论与我们能自信地说的话

在自定义域名上发布
准备分享时将项目发布到你自己的域名。

艾达常被冠以“第一位程序员”的响亮称号。这是个有用的简写,但也可能抹平更有趣的事实。争论不仅关乎名誉,更关乎我们如何定义“程序”“计算机”和“作者权”。

“第一位程序员”真正意味着什么(以及为何有人争论)

如果把“程序员”理解为为通用机器写下指令的人,洛芙莱斯有很强的理由被认为符合条件。她在分析机的笔记中描述了生成伯努利数的逐步方法——本质上是让分析机执行非平凡计算的计划。

但历史学家争论此称号的原因包括:

  • 分析机没有完成,因此该程序当时无法运行并验证。
  • 方法的某些部分可能反映了与巴贝奇的合作,思想贡献难以完全区分。
  • 早期也存在自动化(如雅卡尔德织机的穿孔卡和若干计算装置),虽不完全等同于通用意义上的机器。

思想与可工作的机器

把“发明计算思想”与“制造一台可工作的计算机”区分开很重要。巴贝奇的主要贡献是架构:提出一个有储存(“store”)、处理器(“mill”)和通过穿孔卡控制的机器。洛芙莱斯的贡献则是解释性与表达性的:她阐明了这类机器可以代表什么,以及如何把一个过程写下来使机器能够执行。

一个程序并不会因为硬件当时不存在而不再是程序。从现代角度看,这就像为尚处于理论阶段的平台写软件,或在芯片还不存在时先指定算法。

在不给历史制造竞争的前提下致谢

尊重地谈论这个时代的一种方式是把它看作跨角色的协作:

  • 巴贝奇:机器设计、数学抱负与长期的迭代开发。
  • 洛芙莱斯:翻译、扩展、解释,以及把抽象过程与通用机器连接起来的罕见能力。
  • 梅纳布雷亚(及其他人):早期描述,洛芙莱斯在翻译后把它们转化为更详尽的形式。

我们可以自信地说:洛芙莱斯的笔记帮助定义了什么是编程——不仅仅是计算,还是把过程以机器可遵循的无歧义形式表达出来。

当今设计程序的实用要点

洛芙莱斯的笔记之所以重要,是因为它们展示了在把想法变成机器可执行计划时应如何思考。即便你从不接触穿孔卡或机械齿轮,核心教训仍能映射到现代程序设计:给工作明确的结构、仔细命名、把重复作为工具,并构建可复用的组件。

留存的教训(仍然相当现代)

结构胜过聪明。 当程序被拆成有明确目的的步骤时,构建与维护都更容易。洛芙莱斯的方法鼓励你在纠结细节之前先设计解决方案的形状

清晰即特性。 她的表格与解释不是装饰——它们是程序的一部分。当将来的你(或队友)能快速跟上逻辑,程序就更可靠。

迭代是工具,不是技巧。 重复(循环)是扩展方法的手段。关键是定义重复的内容、每次变化的部分以及何时停止。

抽象促成重用。 如果一系列步骤能工作一次,你应该能用不同输入再次使用它。这是函数、模块与库的萌芽。

这些在现代工具中如何体现

如果你曾用“通过描述来构建”的工作流——先写需求、迭代计划,然后生成可工作的软件——你已经在重演洛芙莱斯笔记的精神:把过程明确、保持状态清晰、并记录假设以实现可重复执行。这也是像 Koder.ai 这样的工具自然而然融入这一故事的原因。Koder.ai 让你通过聊天界面创建网页、后端与移动应用,但相同的基本原则仍适用:在你生成或修改代码前,用规划模式把“笔记”固定下来,明确输入/输出并保持命名一致,会得到更好的结果。

设计程序时的简单清单

在开始编码前或在调试感觉混乱的问题时,做一次快速检查:

  1. 目标: 你能用一句话说明程序的产出吗?
  2. 输入/输出: 什么进来,什么出来,格式如何?
  3. 分解: 列出 3–7 个主要步骤(若过多就分组)。
  4. 命名: 关键值叫什么?保持一致。
  5. 找到重复: 哪个步骤会重复?每次变化什么?
  6. 停止条件: 每个循环或过程如何结束?如何避免无限工作?
  7. 可复用块: 哪些步骤可提炼成函数供别处使用?
  8. 解释: 读者能否仅凭你的注释或文档理解计划而无需运行?

继续学习(后续阅读)

如果你想强化“先做笔记再编码”的程序设计风格,这些会有帮助:

  • /blog/how-to-write-better-requirements
  • /blog/pseudocode-examples

把这些习惯结合起来,会把编程从“让它能跑”变成“让它可理解”——这正是洛芙莱斯的笔记早已指向的转变。

常见问题

什么是艾达·洛芙莱斯的“首个算法”,用通俗的话怎么说?

艾达·洛芙莱斯的“首个算法”是她在《笔记》中呈现的一套逐步指令,意在由查尔斯·巴贝奇的分析机执行。它著名的原因在于:它将计算视为对存储值进行按序操作的有计划步骤,这与现代编程非常相似,尽管当时那台机器并未完工。

这篇文章想解释什么(不想解释什么)?

本文侧重于洛芙莱斯作品中的编程思想:如何把方法表达为可执行、可检验且易于理解的步骤——而不是试图还原分析机的硬件结构或解决所有历史上的争议。

什么是分析机,它为什么对编程重要?

分析机是一个被设想的通用机器,旨在:

  • 存储数字(“store”,类似内存)
  • 执行运算(“mill”,类似 CPU)
  • 通过穿孔卡接收指令与数据

这个架构重要的地方在于它把执行步骤的硬件规定要执行哪些步骤的程序分离开来——这正是现代计算机所依赖的基本分工。

为什么洛芙莱斯用伯努利数作为示例?

伯努利数在多处数学公式中出现。它们是一个很好的示例问题,因为每一个新值都依赖先前的值,需要多次运算中间存储可重复的步骤——正是用可编程机器测试结构化计算能力时需要的条件。

洛芙莱斯的逐步表格有什么重要之处?

步表会强制精确化。它要求你明确说明:

  • 哪些步骤先后发生
  • 每个中间值存放在哪里
  • 何时更新值而不是复用它们
  • 重复从哪里开始、在哪里结束

这就是它与现代伪代码相像的原因:让别人能够在不猜测的情况下“运行”这个过程。

洛芙莱斯的算法如何与循环和迭代相连?

重复是迭代的早期形式:定义一小套步骤,每次执行改变某些内容(例如计数器或部分结果),并在满足条件时停止。在现代代码中,这对应于 for / while 循环,构件包括:

  • 一个计数器
  • 一个变化的状态
  • 一个停止条件
她的方法中为什么变量和精确符号这么重要?

因为机器不能像人一样靠上下文“记住”事情。变量式的标记能让你跟踪:

  • 哪个量正在被更新
  • 哪些值必须保留以供后续使用
  • 哪些临时值可以被覆盖

这些标记能显著减少长过程里最常见的错误:把相似的量搞混。

文章中提到的“抽象与重用”在洛芙莱斯的笔记里是什么意思?

抽象就是聚焦重要的部分并有意隐藏那些不重要的细节。洛芙莱斯的《笔记》把方法机械细节区分开来:

  • 算法描述意图(例如计算伯努利数)
  • 机器或实现负责执行细节(值放在哪里,如何运算)

把方法表达清楚后,我们就可以像用函数或模块那样重复使用它:命名、接收输入、产生输出,并在不需要时隐藏内部步骤。

艾达·洛芙莱斯真的是第一个程序员吗,还是一种神话?

这个称号有争议,因为:

  • 分析机没有完工,因此当时无法实际运行并验证程序
  • 洛芙莱斯与巴贝奇有合作,作者界限并不总是清晰
  • 在某种程度上,早期也有别的自动化存在(例如织机的穿孔卡)

更稳妥的说法是:洛芙莱斯的《笔记》明确界定了什么是编程——不仅仅是计算,而是把一个过程以无歧义的方式写出来,让机器能够跟随。

本文给当今程序设计的实践性建议有哪些?

在把想法变成机器可执行的计划时,洛芙莱斯的《笔记》给我们不少实用启示。即便你不接触穿孔卡或机械齿轮,核心教训仍然适用于现代程序设计:

  1. 明确目标。能用一句话说出程序的产出吗?
  2. 输入/输出:什么进来,什么出去,格式如何?
  3. 分解:将任务拆成 3–7 个主要步骤(若超过 20 个则分组)。
  4. 命名:给关键值一致的名字。
  5. 找到重复:哪个步骤会重复?每次改变什么?
  6. 停止条件:什么会结束循环或过程?如何避免无限循环?
  7. 可复用块:哪些步骤可以提炼成函数用于别处?
  8. 解释清楚:读者能否仅凭注释或文档理解计划?

相关阅读:/blog/how-to-write-better-requirements/blog/pseudocode-examples

Related posts