BQN:什么是原语?
摘要
这篇文章由Marshall Lochbaum撰写,讨论了BQN数组编程语言中选择原语背后的哲学,主张原语应是发现的而非发明的,并对符号与名称进行了对比。
暂无内容
查看缓存全文
缓存时间: 2026/06/02 21:34
# BQN:什么是原语?
来源:https://mlochbaum.github.io/BQN/commentary/primitive.html
人们有时会好奇 BQN 中一组原语是如何选出来的。数组编程的门外人可能会认为 APL 的“大创意”就是简单地用符号代替名称来书写最常见的任务——就连 Dijkstra 也说过类似的话,称 APL 为一个“小把戏的集合”!我不认为这完全正确,所以我想解释一下我的个人观点:为什么将少数特殊操作称为“原语”并赋予专用符号是有意义的。虽然我认为这部分与某些数组设计者的想法有重叠,但在此仅代表我个人的看法。
## 名称与符号 (https://mlochbaum.github.io/BQN/commentary/primitive.html#names-versus-symbols)
本文大部分内容将讨论为什么各种函数**不应该**被视为原语,因此先讨论符号的缺点以及为什么我们不会希望所有东西都用符号表示是合理的。
- 词语传达含义更精确
- 词语可以更复杂的方式修饰或组合
- 有大量含义已确定的词语可用
- 词语更容易输入和发音
一个总体主题是:词语——即语言而非符号——提供了更多的可能性和细微差别。如果有两个相关的概念,通常可以给它们起名,使关系与区别都清晰(例如 `KeepBefore` 和 `KeepUpTo`)。用符号则更难:只有少数广泛的关系比如镜像反射(这极易出错!)和并置可用。但强调细微差别的词语也可能成为累赘。如果只有唯一一种可能,那么一个精心选择的符号可能更好地表示它,并且更容易记忆。
在 BQN 中,句法角色也是一个因素。大小写和下划线允许任何词语以任何角色书写,而原语有固定的角色。如果一个值既可能被当作函数调用,也可能作为参数传递,那么使用名称会更方便。
## 原语哲学 (https://mlochbaum.github.io/BQN/commentary/primitive.html#primitive-philosophy)
语言设计是发现的过程还是发明的过程?当然是两者兼有,但我认为原语设计主要应该是发现。也就是说,如果一个函数感觉像是被“发明”出来的——更糟糕的是,像是被“设计”出来的——那它就不适合成为 BQN 的原语。发现意味着所讨论的事物在某种意义上是独立于描述者的,因此如果两个不同的人发现了某样东西,那它会是完全相同的东西。一个发明出来的东西总会带有其发明者的印记,那些本可以有所不同的小决策。
事情往往没有这么绝对,而且有点讽刺的是,一种语言中所有原语的**集合**绝对是被设计出来的。虽然我认为给更接近原语特性的东西赋予符号,给不那么原语的东西赋予名称是个好主意,但这为不同的设计留下了空间:可以像一个平衡点那样更多使用符号(如 APL),也可以更多使用名称(如 Python),可以侧重于提供不同的功能,或者在提供类似功能的少数原语中选择不同的组合。
我认为某些设计行为是可以接受的,如果目的仅仅是为了让底层的原语功能更易用。例如,区间(`↕`)结合了两个定义域不相交的原语函数,而秩(`⎉`)将几个数字塞进了一个顺序任意的列表。我仍然认为这些多少有些遗憾,但为了增加便利性而可以接受。
## 原语实践 (https://mlochbaum.github.io/BQN/commentary/primitive.html#primitive-practice)
是否存在等待被发现的“原语”?我认为是的:像加法、映射、连接一个列表到另一个列表之类的基本概念,任何能够发展编程的社会都会重新发明它们,并且它们会有完全相同的含义。但这算是一种模糊的断言,我不打算深入探讨某事物是否“实际上”存在这种问题。更实际的做法是从一些我认为与思维工具质量相关的特性入手:
- 简单的数学描述(更好的是不止一种)
- 基于约束的简单规范(同上)
- 可用于实现其他操作
- 没有或者很少有有用的变体
这些特性往往相互关联:虽然它们中没有一个必然蕴含另一个,但一个函数只满足其中一半似乎很罕见。除了经验观察之外,还有些论点可以解释为什么我们预期会是这样。例如,如果一个函数的结果可以用两个独立约束集中的任意一个来指定,那么定义对某些参数不同的变体可能就没有意义,因为它不会遵循同样的约束。而且通常复杂事物是由简单事物实现的,因此一个能够简洁实现其他东西的函数往往本身更简单。
更令人惊讶的是,符合这些标准的操作往往还具有一些其他好处:
- 需要考虑的边界情况更少
- 跨多个领域相关
- 高效的实现(理论上和硬件上)
- 原语的组合能提供有用的功能
- 原语之间的关系可用于证明
同样,某些属性似乎直观地与上述属性相关,但其他属性的联系并不那么明显。它们是我多年来在编程和设计中观察到的广泛模式。
## 算术原语 (https://mlochbaum.github.io/BQN/commentary/primitive.html#arithmetic-primitives)
我可以指出,已经有一类函数毫无疑问符合上述描述,那就是算术函数 `+-×÷`。它们是必不可少的工具,有趣的是,几乎每种语言都用符号(不一定相同)来表示它们。
为什么像加法这样广泛有用的函数会存在呢?它是数学的一个例子(即使你不认为编程是数学,它肯定也能用数学来描述),其结构比直接推理所能解释的更加结构化。这是因为数学本身会施加结构,一个数学对象的事实可以约束另一个对象的行为。这种结构可能表现为数学家能够证明的定理、他们无法证明的定理,或者有时被称为“民间定理”的更模糊概念。一个很好的例证是**乌拉姆螺旋** (https://en.wikipedia.org/wiki/Ulam%27s_spiral),即素数倾向于遵循算术模式。有一些关于特定模式的证明,以及关于其他模式的猜想。更广泛的民间定理——素数会在**任何**简单的算术排列中显示模式——过于模糊甚至无法证明,但有大量证据支持,并且对从事该领域工作的数学家具有实际用处。
| 定义 | 精确 | 模糊 |
|--------|------------------|-----------------------|
| 应用 | 具体 | 通用 |
| 算法 | 原语 | 设计模式 |
民间定理很像编程中的设计模式,它们可以指导或描述一个实现,但不会直接出现在代码中。相比之下,原语是精确定义的操作,因此它既能用于组织,也能用于实际代码中。
原语遵循数学规则——例如减法撤销加法。一系列原语可以用这些规则进行代数变换,变成一个执行相同计算的不同序列。符号非常适合代数操作,因为阅读它们的开销较低,更容易识别符号组并移动它们。程序员仍然需要选择做什么更改,但原语符号使得正确执行这些更改变得更容易。
## 使用原语编程 (https://mlochbaum.github.io/BQN/commentary/primitive.html#programming-with-primitives)
APL 添加了一些在其他语言中不常见的算术原语,但它的主要贡献是数组原语。包括 BQN 在内的一些后来 APL 家族语言还添加了组合子——用于处理函数的隐式原语(数学中确实有复合 `∘`;区别在于 APL 的组合子用于一元或二元函数)。
算术、函数和数组这三个领域的主要原因很简单:它们是 BQN 中用于计算的主要类型。有趣的是,没有命名空间原语。在 BQN 中,命名空间用于代码组织,而非计算。类似情况发生在 C 语言的数组上:它们不是计算的对象,所以虽然有操作指针的运算符(加法、引用和解引用),但没有针对数组的运算符。使 BQN 数组更适合在其上定义原语的一个因素是它们是不可变的。
如今许多流行语言都有用于处理数组的标准函数或方法,例如连接、反转和映射。但它们通常被视为工具函数而非原语,并且在某些情况下附加了额外的功能,使其更复杂且更不易组合(例如 JavaScript 的映射会向操作数传递额外参数)。
BQN 的原语集合在设计时更强调简单和一致,当然每个原语都用单个符号表示。在这样的系统中,单个原语的好处(如更少的边界情况和多领域适用性)相互强化。代数操作也成为重构、修改或优化代码的安全强大工具。我认为认识到某些函数具有“原语性”对设计 BQN 非常有帮助,理解各个原语及其关系使得更容易快速开发出正确且通用的代码。
相似文章
七大编程原语言(2022)
一篇文章探讨了七种构成大多数现代编程语言基础的编程语言原型(原语言),认为学习植根于这些原型的基础知识比选择特定语言更重要。
每个 Agent 框架中都缺失的关键原语:受保护区域
作者指出,当前的 AI 编程 Agent 因缺乏类似编译器的边界约束而面临“逻辑漂移”问题,并建议 Agent 框架需要引入可执行的受保护区域,以防止未经授权或有害的代码修改。
以理论构建的视角阅读编程
本文推荐 Peter Naur 的著作《编程即理论构建》,主张编程的本质在于构建和传达对软件的心理模型,而不仅仅是编写代码。
编程作为理论构建(1985)
这篇彼得·诺尔(Peter Naur)于1985年发表的论文指出,编程本质上是一种理论构建活动,程序员需要深入理解问题领域,而不仅仅是生成代码。
如果 EndBASIC 中没有 BASIC 会怎样?—— Julio Merino 著
Julio Merino 探讨了 EndBASIC 的未来,研究是否应移除 BASIC 语言层,以便将底层的 Rust VM 和图形引擎重新用于更现代或更通用的开发需求。