广义 plusequals

发布: (2026年4月25日 GMT+8 05:34)
4 分钟阅读

Source: Hacker News

2026-04-24

Introduction

我一直在开发一个半成品语言。它大多是垃圾,但出现了一个我觉得相当有趣的语法想法。

在许多语言中,下面两种写法是等价的:

x = x + 1
x += 1

重新赋值很酷,因为它是词法作用域的,易于推理(而变异则不好,因为它不是词法作用域的)。

新的想法是,用一个关键字(这里是 alt)来泛化所有中缀运算符,而不是使用特殊符号(如 +=),于是下面两种写法是等价的:

x = x + 1
alt x + 1

谁在乎呢?它甚至并没有更短,对吧?

Comparison with Python

l = l[4]=999
l = l[:4] + [999] + l[5:]

以及:

x = x.n.=2
x = dataclasses.replace(x, n=2)

现在我们来设定几个嵌套数据的例子:

cat = Cat(age=3)
l = [1, [2, cat], 4]

如果想把猫的年龄改大一点,可以这样写:

alt cat.age.=8

更有意思的例子是,对深度嵌套的 l 进行重新赋值,使其中的猫变老,而不改变原始的猫对象:

alt l[1][1].age.=9

这会让 l 变成:

[1, [2, Cat(age=9)], 4]

alt 语句糖背后到底做了什么,使我们没有改变原始的猫?大致如下:

_1 = l[1]       # _1 = [2, Cat(age=3)]
_2 = l[1][1]    # _2 = Cat(age=3)
_2 = _2.age.=9  # _2 = Cat(age=9)
_1 = _1[1]=_2   # _1 = [2, Cat(age=9)]
l  = l[1]=_1    # l  = [1, [2, Cat(age=9)], 4]

我的新语言还有一个很棒的特性——你可以用波浪号把普通二元函数变成中缀形式,这意味着可以做类似的有趣操作:

alt l~push~5

从而使 l 变为:

[1, [2, Cat(age=9)], 4, 5]

Thoughts

  • 我不喜欢变异,但我确实喜欢能够简洁地更新深层嵌套数据。这种语法让你在只有不可变数据结构的语言中也能实现“可爱”的更新。
  • Haskell 是怎么做的?还有没有其他类似的语法?
  • 我的语言的大致计划是:假装所有数据结构都是不可变的,但在编译时,如果程序结构可以用等价的可变实现来提升性能,就使用可变实现。(这在某种程度上是 Swift 中可变值语义的逆向做法,并且会与 Rust 的借用检查器共享一些实现细节。)
  • 在某些方面,这与一些更早的想法相反。
  • 在我的语言里,我还加入了 Rust 的 ? 运算符的广义版本
0 浏览
Back to Blog

相关文章

阅读更多 »