Nature 编程语言一直计划支持 enum 结构,但是由于没有思考好是添加类似 C 一样的基础 enum 还是类似 Rust 一样强大的 enum,所以这个功能一直被搁置着。最近想通了,我可以先设计一个基础的 enum,后续若有需求进一步扩展不就行了。这是基础语法设计
type color = enum {
RED = 1, // Counting starts from 1
GREEN,
BLUE,
}
// 自定义基础类型
type color = enum:i32 {}
// 可以使用 match 进行穷尽检查, 支持 impl
fn color.to_string(self):string {
match self {
color.RED -> 'red'
color.GREEN -> 'green'
color.BLUE -> 'blue'
}
}
// Usage example
var c = color.RED
print(c.to_string())但完成基础 enum 开发后,我又开始贪了! 现在 AI 这么厉害 (๑•̀ㅂ•́)و✧ 不如直接让 AI 一步到位,支持类似 Rust 中的高级 enum 用法支持,于是我参考 Rust、Swift 设计出了这样的语法
type option = enum {
some(int), // 只支持 tuple 组合,不支持 struct
none,
}
fn main() {
var opt = option.some(100)
var opt2 = option.none
var value = match opt {
option.some(v) -> v
option.none -> -1
}
assert(value == 100)
}经过一天一夜的努力,AI 成功耗光了我 Antigravity 两个账号的 Claude Opus 4.5 周使用限额,但是连一个能编译成功的用例都没跑出来 🤦♂️,看来这种复杂任务对它来说还是有些吃力。

不过鉴于 AI 已经写了不少代码,经过我又一天的修修补补,终于成功运行起来。但是经过这两天的接触,我越发觉得这种设计在 Nature 中不够协调,尤其是类似 write(string) 这样的表达方式非常的奇怪,Nature 中找不到任何的语法能够对应这种表达方式。并且增加 基于 Nature 整体的学习曲线会进一步提升,这与 Nature 简洁优雅的设计理念相冲突。于是我狠下心来,打算直接放弃这个功能,毕竟 AI 写的代码丢掉我也不心疼 🚮
不过还是有些不甘心的,有空的时候我继续调研所有支持 sum type 的编程语言,希望能从中找到一些灵感,比如 Haskell, Ocam, Swift, Kotlin, Zig 等等,这里不得不提 Rust 的 enum 设计,基于其灵活的 struct 设计,配合 match 语法使用非常自然 👍。
enum Message {
Quit, // struct Quit;
Move { x: i32, y: i32 }, // struct Move { x: i32, y: i32 };
Write(String), // struct Write(String);
ChangeColor(i32, i32, i32), // struct ChangeColor(i32, i32, i32);
}
match msg {
Message::Quit => println!("Quit variant has no data."),
Message::Move { x, y } => println!("Move to x: {}, y: {}", x, y),
Message::Write(text) => println!("Text message: {}", text),
Message::ChangeColor(r, g, b) => println!("Change color to R:{}, G:{}, B:{}", r, g, b),
}虽然 Nature 仅采用了 tuple 模式,与 Swift 类似。我可以解释这是 enum + union + tuple 组合而成的语法设计,但还是比较突兀。并且有一个关键问题,Nature 中已经有类似 TypeScript 的 union 类型设计,这种 union 本质就是一种简化的 sum type,nature 的 Option<T> 和 Result<T, E> 也是基于此设计,语法示例如下
type shape = int|float
type nullable<T> = T|null
type throwable<T> = T|error
fn main() {
shape s = 12
if s is int v { // auto insert var v = s as int
println(s)
}
var val = match s {
is int v -> v
_ -> 0
}
}可以看到通过 is 关键字可以对 union 进行自动解构,这是已有的语法,类似于 Rust 中的 if let Some(u) = temp。但是 Nature 中的 is 关键字仅适用于 union 类型,如果 sum type enum 想要兼容这个语法需要进行额外的工作。总结来说 sum type enum 在 Nature 中并不是那么自然优雅! 甚至和已有的 union 存在一定的语义冲突。
于是我重新思考如何设计一个更加自然优雅的 sum type 支持。在参考了大量的编程语言后,最终决定还是进一步增强现有的 union,而不是基于 enum。 现有的 union 类型无法应对复杂场景,比如 type shape = int|int|(int, int)|foo_t 这类存在重复类型的情况,虽然可以通过定义 struct 解决,但终究还是过于繁琐。
其实解决办法到这里已经呼之欲出了,只需要为现有的 union 的增加 tag 构成的 tagged union 不仅够解决相关问题,还能得到一个完整的 sum type 设计,第一版语法设计类似于 haskell
type nullable<T> =
| none
| ok(T)语法上虽然简洁,但是存在一个严重的问题,| 关键字不是封闭的,ok(T) 和 none 在语义上具有全局性,不受 nullable 的约束。也就是 nullable.none 和 none 的区别。
类似 struct/enum 使用的 {} 声明方式则是封闭的且具有约束性。所以使用 union{} 来声明 tagged union 是可选的方式,并且我还进一步简化了 tagged union 的初始化方式,对 tuple 类型可以自动进行解构、match 穷尽检查等等。最终得到了下面的设计
type ellipse_t = struct{
int rx
int ry
}
type shape = union{
int circle
int square
(int, int) rectangle
ellipse_t ellipse
void point
}
// 传统 c like union 赋值
// shape s = shape{sllipse: ellipse_t{rx:1, ry:2}}
// nature 中采用简化的赋值方式
shape s = shape.ellipse(ellipse_t{rx:1, ry:2})
// shape s = shape.rectangle((1, 2))
// 这里两个括号有些多余了,所以对 tuple 类型的初始化进行了优化处理,当然原有方式也是支持的。
shape s2 = shape.rectangle(1, 2)
// 基于原有的 is union T 的方式,扩展为 is union tag
if s is shape.ellipse v {
// auto insert: v = s as shape.sllips
println(v.rx, v.ry)
}
// nature 的 tupe 支持解构赋值,等同于
// if s is shape.rectangle v
// s is shape.rectangle(x, y) 省略空格的方式也是支持的
if s2 is shape.rectangle (x, y) {
// auto insert var (x, y) = s as shape.rectangle
}
// match 对 tagged union/union/enum 类型都会进行穷尽检查
var v = match s {
is m.shape.circle v -> v * PI * PI
is shape.square v -> v * v
is shape.rectangle(width, height) -> width * height
is shape.ellipse v -> v.rx * v.r * PI
is shape.point -> 0
}
将类型设为 void 可以很自然的表示仅使用标签无需关联值的情况,Zig 的 enum(union) 也采用了类似策略。tagged union 同样支持泛型和 impl
type result<T> = union{
T some
void none
}
fn result.to_string():string {
return match self {
is result.some -> 'some'
is result.none -> 'none'
}
}
fn main() {
// 如果 r 的类型已知,则可以进行泛型类型的简单推导
// result<T> r = result.some(123)
var r = result<int>.some(123)
if r is result.some v {
assert(v == 123)
}
r = result<int>.some(352)
match r {
is result.some v -> {
assert(v == 352)
}
is result.none -> {
assert(false)
}
}
}经过这一波三折,AI 模型的使用额度已耗尽,我只能通过“古法编程”实现这个方案 🧑💻,再一次经过两天的奋斗完成了相关的开发并合并到了 master 分支。相关文档将会在新的大版本发布时更新。可以参考的测试用例 20260201_00_tagged_union.testar