本文翻译自 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 中,函数接受程序的剩余部分作为输入,返回程序作为输出。
前缀表示法的优势:
- 不可能发生栈下溢 — 不依赖数据栈,而是存储组合的部分函数
- 更贴近函数组合的数学模型 — 评估器可以单次遍历完成读取、解析和求值
- 流式处理能力 — 结果可以在计算时立即输出到输出流
- 延迟加载优化 — 函数可以只读取所需的数据到内存
- 天然支持事件处理 — 程序可以求值为一个状态机函数,处理追加到程序的任何额外数据
全形态类型系统
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 中非常高效,因为:
- 前缀连接语法启用的”急切”求值模型
- 非递归的评估器实现,最小化递归调用的内存开销
以下示例使用递归从冒号分隔的 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 提供了一种清新的替代思路。虽然它还不足以用于生产环境,但探索其设计理念本身就是一次有价值的思维旅程。
关键要点
- 极简语法 — 仅三种元素(操作符、分隔符、操作数),任何 UTF-8 文本都是有效程序
- 前缀连接式 — 颠覆传统后缀式设计,避免栈下溢,支持流式处理
- 全形态类型 — 无需传统类型系统,所有数据通过统一接口处理
- 同像性 — 代码即数据,数据即代码
- C++ 可嵌入 — 作为头文件库轻松集成到现有项目
- 早期阶段 — 概念验证阶段,欢迎社区参与开发
如果你想深入了解或参与开发,可以访问 Om GitHub 仓库。