1. 从“表格”到“语言”:一次软件工程的范式革命
如果你在办公室里问一圈,十个人里可能有九个都用过Excel,但恐怕没几个人会把它看作一门“编程语言”。然而,从软件工程的视角看,电子表格确实是这个星球上使用最广泛的编程环境,用户量级远超Python、JavaScript等任何专业语言。这个事实本身就蕴含着一个巨大的机会:如果我们能把编程语言研究领域那些成熟的思想——比如类型系统、高阶函数、抽象机制——注入到Excel这样的主流软件中,会发生什么?这不仅仅是给表格加几个新函数,而是一场旨在为数亿用户赋能的、静默发生的范式革命。我作为一个长期混迹在软件工程和PL(编程语言)研究交叉地带的人,对微软研究院与Excel产品团队合作的这个“Calc Intelligence”项目格外着迷。它不是在实验室里造一个炫酷但没人用的新语言,而是选择去“改造”那个已经无处不在的“世界语”——电子表格。今天,我就来拆解一下这场变革背后的核心逻辑、已经落地的特性,以及它预示的未来,希望能给从事工具设计、开发者体验或任何希望提升用户生产力的朋友一些启发。
2. 核心设计思路:为何要从PL研究中汲取灵感?
2.1 识别电子表格作为编程语言的本质缺陷
传统观点认为电子表格是给“业务人员”用的,而“真正”的编程是开发者的领域。这种割裂造成了巨大的效率鸿沟和认知负荷。当我们用软件工程的眼光审视电子表格,会发现它虽然拥有图灵完备的计算能力(通过公式和引用),但在语言设计层面存在几个关键短板:
- 弱化的数据类型系统:一个单元格里可以放数字、文本、日期,甚至错误值,但表格本身缺乏对结构化数据(如数组、记录/对象)的原生、一等公民支持。用户常常用多行多列来“模拟”一个数组,用合并单元格或注释来“暗示”一条记录,这种表示既脆弱又难以操作。
- 匮乏的抽象与封装机制:复制粘贴是主要的“代码复用”手段。复杂的计算逻辑被拆解成无数个分散在各处的公式,一旦业务逻辑需要调整,修改点可能遍布整个工作表,维护成本极高。虽然Excel有VBA,但那要求用户切换到另一个完全不同的编程范式(过程式、文本编辑),门槛陡增。
- “隐式”的计算模型:公式是隐藏的,计算依赖关系是间接的(通过单元格引用)。对于稍复杂的模型,用户很难一眼看清数据流和计算链条,这给调试、理解和协作带来了巨大困难。
这些缺陷,恰恰是编程语言研究在过去几十年里重点攻克的问题。因此,将PL思想引入电子表格,不是生搬硬套,而是对症下药。
2.2 确立“用户中心”与“渐进增强”两大原则
Calc Intelligence项目最聪明的地方在于其方法论。它不是推倒重来,而是坚持了两个核心原则:
原则一:用户中心,而非技术中心。所有改进都必须围绕终端用户(分析师、财务、运营等)的实际领域和心智模型展开。例如,数据类型不应该只是计算机科学中的int、string,而应该是“股票代码”、“部门名称”、“地理坐标”这样的领域类型。函数也不应只是数学运算,而应反映用户的业务抽象,比如“计算季度环比增长率”、“合并客户订单”。
原则二:渐进增强,平滑过渡。任何新特性都不能破坏现有数亿份表格文件的兼容性,也不能改变用户已经熟悉的基本操作。新能力应该像“超能力”一样,在用户需要时自然浮现,而不是强迫所有人改变习惯。这意味着改进必须建立在现有公式语法和网格交互的基石之上。
基于这两点,团队锁定了几个关键的改造方向,它们都直接对应着上述缺陷。
3. 核心特性解析:如何让表格“编程”更强大?
3.1 动态数组:将“数组”提升为一等公民
这是最早落地、也是影响最深远的特性之一。在过去,如果你写了一个公式=SORT(A2:A100),结果只能显示在单个单元格里(通常是排序后的第一个值)。要得到完整结果,你必须使用古老的“数组公式”(按Ctrl+Shift+Enter),或者将公式拖拽填充到一片区域,操作繁琐且不直观。
动态数组彻底改变了这一点。现在,你只需在单个单元格输入=SORT(A2:A100),按下回车,排序后的整个数组会自动“溢出”到下方相邻的单元格区域。这个结果区域被视为一个整体,一个“一等公民”的数组值。
背后的PL思想:这实现了“数组作为一等值”。在编程语言中,一等公民意味着该值可以像数字、字符串一样被赋值、传递、作为函数参数和返回值。在Excel中,动态数组让数组能直接由任何公式产生,并能被其他公式引用(通过“#”符号,如=SUM(SORT(A2:A100)#))。这极大地简化了多步骤数据转换的链条。
实操要点与避坑指南:
- 引用溢出区域:使用“#”符号(如
B2#)可以引用整个动态数组结果区域,即使源数据变化导致数组大小改变,引用也会自动适应。 - “#溢出!”错误:如果公式计算的数组需要溢出到的区域内有非空单元格,Excel会报此错误。你需要清理目标区域或调整公式。
- 与旧函数兼容:许多旧函数(如
SUMPRODUCT)能天然处理数组,但有些需要配合新的FILTER、UNIQUE、SEQUENCE等动态数组函数才能发挥最大威力。我的经验是:在构建新的数据流程时,优先使用动态数组函数族,它们的设计更一致,逻辑更清晰。
3.2 Lambda函数与Let表达式:引入高阶抽象
这是将函数式编程的核心能力注入表格公式语言的里程碑。LAMBDA函数允许用户在不借助VBA的情况下,创建自定义的、可复用的函数。
基本语法:=LAMBDA(参数1, 参数2, ..., 计算公式)。例如,定义一个计算直角三角形斜边的函数:=LAMBDA(a, b, SQRT(a*a + b*b))。但这只是一个定义,需要配合LET或命名来使用。
LET表达式:它允许你在一个公式内部定义局部变量,极大提高了复杂公式的可读性和可维护性。语法:=LET(name1, value1, name2, value2, ..., calculation)。
组合使用:真正的力量在于组合。你可以用LET给LAMBDA定义命名,从而创建自定义函数。
=LET( Hypotenuse, LAMBDA(a, b, SQRT(a*a + b*b)), // 定义函数 Hypotenuse(3, 4) // 调用函数,返回5 )更强大的是,你可以通过“名称管理器”将这个LAMBDA函数保存为一个全局名称(如Hypotenuse),之后就可以在整个工作簿中像内置函数一样使用=Hypotenuse(B1, B2)。
背后的PL思想:这引入了高阶函数和词法作用域。LAMBDA本身可以作为值被传递(例如,作为MAP或REDUCE函数的参数),实现了行为的抽象。LET提供了清晰的变量作用域,避免了公式中重复计算的混乱。
实操心得:
- 从封装重复逻辑开始:如果你发现同一个复杂的公式片段在多个地方出现,那就是提取为
LAMBDA函数的最佳时机。 - 调试技巧:复杂的
LAMBDA函数难以调试。一个好方法是:先用LET在单个单元格内逐步构建和测试你的计算逻辑,确保每一步结果正确,最后再将核心计算部分包装成LAMBDA。 - 性能考量:
LAMBDA函数在每次被调用时都会重新计算其主体。对于计算量巨大且被频繁调用的函数,需注意性能。目前,它更适合封装中小型的数据转换和业务规则逻辑。
3.3 数据类型:超越文本和数字的结构化值
这是让单元格内的值“活”起来的关键一步。现在,一个单元格可以包含一个完整的“记录”类型数据,例如从外部数据源引入的“股票”类型,其单元格不仅显示公司代码(如“MSFT”),还可能包含股价、涨跌幅、公司名称等丰富字段,这些字段可以被其他公式直接引用。
例如:单元格A1包含一个“股票”数据类型(来自Microsoft 365的数据类型库)。你可以写公式=A1.Price来获取实时股价,=A1.Change来获取涨跌幅。这看起来就像在操作一个对象属性。
背后的PL思想:这是对领域特定类型(DSL Types)和记录(Record)类型的支持。它允许数据携带丰富的元数据和结构,使公式的意图更明确(=Revenue * TaxRate比=B2 * C2清晰得多),并且能直接与外部实时数据源连接。
实操要点:
- 数据来源:目前主要通过“数据”选项卡中的“数据类型”库获取,涵盖股票、地理、化学、影视等多种领域。
- 公式引用:使用“.”操作符来访问字段。字段列表会在你输入“.”后自动弹出,体验类似代码补全。
- 与动态数组结合:你可以用
FILTER函数过滤出所有“股价高于100的股票”,结果仍然是一组股票数据类型,可以继续访问其字段。这种组合创造了强大的数据流处理能力。
4. 前沿探索:表格编程的未来形态
Calc Intelligence团队并未止步于已发布的特性,他们的研究原型揭示了更激动人心的未来。
4.1 计算视图:让“隐式”的代码显形
这是对我启发最大的一个概念。传统编程是“代码为主,数据在后”,而表格编程是“数据可视为主,代码隐藏”。这带来了“黑盒”问题。“计算视图”旨在提供一个并行的、文本式的代码视角。
想象一下,在Excel网格旁边,有一个并排的面板,里面以结构化的文本形式(也许是类似函数式编程的语法)展示当前工作簿中所有公式的逻辑依赖关系、函数定义和数据流。这个视图可以支持注释、代码折叠、语法高亮,甚至简单的重构操作(如重命名变量)。
它的意义在于:
- 提升可读性与可维护性:对于复杂的财务模型或工程计算,维护者可以快速理解全局逻辑,而不是在成千上万个单元格中跳转。
- 辅助调试:像设置断点、单步执行查看中间结果这样的调试功能,在“计算视图”中更容易实现。
- 促进协作:开发者与领域专家可以有一个更接近传统代码的沟通界面,便于代码审查和知识传递。
这并非要取代网格视图,而是提供一种“双重表示”,让用户可以根据任务在“数据视角”和“逻辑视角”间无缝切换。
4.2 弹性工作表定义函数:从示例到泛化
这是对“由工作表定义的函数”概念的进一步深化。设想一个场景:用户在一个固定大小的数据块(比如一个5x5的表格区域)上定义了一个计算过程(例如,对区域中的每个值应用一个复杂的税费计算)。这个定义被捕获为一个函数。
“弹性”要解决的问题是:如何让这个函数自动适用于任意大小的输入数组?传统方法需要用户理解循环或映射的概念。而研究团队探索的是一种“基于示例的泛化”技术。系统通过分析用户在固定示例上的操作意图(比如,计算是针对每一行,还是每一列,或是某个特定模式?),自动推断出函数在更大或不同形状数据上的行为逻辑。
这背后的挑战是巨大的,属于编程合成和意图推断的范畴。但如果成功,它将允许用户通过操作一个具体的、小规模的数据示例,就创建出能处理海量数据的通用函数,极大地降低了定义复杂数据转换流程的门槛。
5. 对开发者与工具设计者的启示
微软的这个项目不仅仅关乎Excel,它为我们所有从事软件工程、工具设计和用户体验的人上了一堂生动的课。
- 拥抱“存量”用户,而非只追求“增量”:最大的影响力往往来自于改进那些已经被广泛使用的工具,而不是创造一个新工具去教育用户。理解并尊重用户现有的心智模型和工作流至关重要。
- PL研究具有巨大的实用价值:类型理论、函数式抽象、语言设计原则并非学术象牙塔里的玩物。当它们被巧妙地应用到主流生产工具中时,能产生指数级的效用提升。
- 跨学科协作是创新的催化剂:这个项目成功的关键在于编程语言研究员、人机交互专家和产品工程师的深度合作。技术可行性必须与用户体验的平滑性紧密结合。
- “渐进式革命”是可行的路径:通过动态数组、LAMBDA等特性,Excel正在不动声色地将数百万用户引向更强大、更结构化的“编程”方式。这种平滑的过渡比激进革命更容易被接受。
从我个人的实践来看,即使你现在不开发电子表格应用,这些思想也值得借鉴。例如,在设计内部低代码平台、数据分析工具或任何面向非专业开发者的生产力工具时,思考如何引入“一等公民的数据结构”、“可复用的行为抽象”以及“多视角的表征”,都能显著提升工具的威力和用户体验。最终,我们的目标不是让每个人都成为程序员,而是让每个人都能更高效、更可靠地驾驭计算的力量。Calc Intelligence项目正在电子表格这个最广阔的战场上,将这一愿景变为现实。