NEE's Blog

Om:一种极简的连接式编程语言

February 25, 2026

本文翻译自 Om: Main Page,原载于 Hacker News。

引言

在编程语言设计领域,复杂度的增加往往是不可避免的——新特性、新语法、新抽象层层出不穷。然而,Om 语言选择了截然不同的道路:极致简洁

Om 是一种:

  • 连接式(Concatenative)、同像性(Homoiconic)的编程和算法符号语言,具有:
    • 极简语法,仅由三种元素组成
    • 前缀表示法,函数直接操作程序的剩余部分
    • 全形态类型(Panmorphic typing),允许无数据类型编程
  • 易于解析的数据传输格式
  • Unicode 正确:任何 UTF-8 文本(不含 BOM)都构成有效的 Om 程序
  • C++ 库形式实现,可嵌入任何 C++ 或 Objective-C++ 程序

核心语法:仅三种元素

Om 程序由三种元素组成:操作符(Operator)分隔符(Separator)操作数(Operand)

操作符:由反引号、操作数大括号或分隔符代码点组成的任意序列
分隔符:任何空白字符(空格、制表符、换行等)
操作数:由大括号 {} 包裹的任意内容

这种设计意味着 Om 程序本身就是数据,数据也可以是程序——这正是同像性的本质。

前缀表示法:颠覆传统的连接式语言

与 Forth、Joy 等后缀式连接语言不同,Om 采用前缀表示法。在 Om 中,函数接受程序的剩余部分作为输入,返回程序作为输出。

前缀表示法的优势:

  1. 不可能发生栈下溢 — 不依赖数据栈,而是存储组合的部分函数
  2. 更贴近函数组合的数学模型 — 评估器可以单次遍历完成读取、解析和求值
  3. 流式处理能力 — 结果可以在计算时立即输出到输出流
  4. 延迟加载优化 — 函数可以只读取所需的数据到内存
  5. 天然支持事件处理 — 程序可以求值为一个状态机函数,处理追加到程序的任何额外数据

全形态类型系统

Om 没有传统的数据类型——每个数据值都由操作数表示。

Om 使用独特的全形态(Panmorphic)类型系统(源自古希腊语 πᾶν “全部” + μορφή “形式”),所有数据值都通过通用的不可变接口暴露。任何操作都接受任何操作数作为有效输入,并通过其包含的程序(操作符、分隔符和操作数的序列)来查询数据。

代码示例

让我们看一些实际的 Om 代码:

基本操作

{Hello, world!}

这是一个包含操作符 Hello,、分隔符和另一个操作符 world! 的单个操作数。

复制和丢弃

copy {A}{B}{C}
→ {A}{A}{B}{C}

copy 操作复制操作数,而 drop 可以用于注释:

drop {This is a comment.} {This is not a comment.}
→ {This is not a comment.}

条件选择

choose {It was empty.}{It was non-empty.}{I am not empty.}
→ {It was non-empty.}

choose {It was empty.}{It was non-empty.}{}
→ {It was empty.}

引用与去引用

dequote {copy} {A}
→ {A}{A}

从操作数中弹出元素

<-[characters] {ABC}
→ {A}{BC}

->[literal] {A}{BC}
→ {ABC}

定义新操作符

define { double-quote {quote quote} } { double-quote {A} }
→ }

Unicode 支持

Om 完全支持 Unicode:

<-[characters] {한글}
→ {한}{글}

递归示例

递归在 Om 中非常高效,因为:

  1. 前缀连接语法启用的”急切”求值模型
  2. 非递归的评估器实现,最小化递归调用的内存开销

以下示例使用递归从冒号分隔的 24 小时时间字符串中提取分钟:

define { minutes { dequote choose {minutes} {} = {:} <-[characters] } } { minutes {1:23} }
→ {23}

技术实现

Om 作为现代、可移植的 C++ 库实现,遵循 Sparist C++ 编码标准。

构建依赖

  • CMake — 构建系统
  • ICU4C — Unicode 支持
  • Boost — C++ 工具库
  • Doxygen + Graphviz — 文档生成

作为头文件库使用

Om 是一个仅头文件的 C++ 库,可以轻松集成到任何项目中:

#include "om.hpp"

int main() {
    Om::Language::System::Initialize("en_US.UTF-8");
    Om::Language::Environment environment;
    // 使用 environment.Evaluate() 评估程序
}

与其他连接式语言的关系

Om 受到了以下项目和理念的启发:

  • Joy — Manfred von Thun 开创性的连接式语言,所有连接式语言之父
  • Why Concatenative Programming Matters — 连接式编程哲学的经典阐述
  • Concatenative Wiki — 社区资源和讨论

当前状态与展望

需要注意的是,Om 目前处于早期”概念验证”阶段。虽然核心设计理念已经成型,但仍需要添加许多操作(如基本数值和文件操作)和优化才能用于实际场景。

语言在达到 1.0 版本之前可能会经历重大变化,这正是参与早期开发的好时机。

个人见解

Om 的设计哲学令人联想到 Unix 哲学:做一件事,并做好它。三种语法元素的极简设计,让我想起了 Lisp 的 S 表达式——同样简单,却蕴含无限可能。

前缀表示法的选择尤其有趣。传统的连接式语言如 Forth 使用后缀表示法和数据栈,而 Om 的前缀方法提供了一种不同的思考方式:程序不仅仅是数据,更是函数的组合

全形态类型系统则是一种激进的简化——如果所有数据都可以通过统一接口处理,为什么还需要类型?这种设计可能不适合所有场景,但它提供了一个有趣的新视角。

对于那些厌倦了现代编程语言复杂性的开发者来说,Om 提供了一种清新的替代思路。虽然它还不足以用于生产环境,但探索其设计理念本身就是一次有价值的思维旅程。

关键要点

  1. 极简语法 — 仅三种元素(操作符、分隔符、操作数),任何 UTF-8 文本都是有效程序
  2. 前缀连接式 — 颠覆传统后缀式设计,避免栈下溢,支持流式处理
  3. 全形态类型 — 无需传统类型系统,所有数据通过统一接口处理
  4. 同像性 — 代码即数据,数据即代码
  5. C++ 可嵌入 — 作为头文件库轻松集成到现有项目
  6. 早期阶段 — 概念验证阶段,欢迎社区参与开发

如果你想深入了解或参与开发,可以访问 Om GitHub 仓库

comments powered by Disqus