Verse 从哪来:函数式 + 逻辑式 + 命令式的混血
Verse 的很多规矩不是设计者任性,是血统。这一页拆开它的三股来源——命令式给你熟悉的执行顺序,函数式给你默认不可变,逻辑式给你「走得通 / 走不通」——再讲清楚事务性内存与结构化并发这两个卖点,为什么对多人在线世界是刚需而不是炫技。
一、三股血统,汇成一门语言
编程语言像菜系,一门语言的口味基本由它的师承决定。Verse 罕见的地方在于,它同时端了三个流派的菜,而且不打算藏起来。
- ▢ 命令式(imperative):你已经会了。「先做这个,再做那个」——蓝图里那根白色执行线就是命令式的可视化形态。Verse 完整保留了这一面:
OnBegin里写着的几行,从上往下依次执行,没有任何玄机。这是你搬家时不用打包的那部分。 - ◇ 函数式(functional):把计算当成一台榨汁机。原料进去、果汁出来,机器本身不留痕迹。这一支的信条是「少改状态、多算返回值」,Verse 从它那里继承了「数据默认不可变」「改值必须显式喊
set」。其实你在蓝图里见过它的一小块飞地:那些绿色的纯节点(Pure)——没有执行线针脚,只吃输入吐输出。Verse 做的事,是把这块飞地变成了主场。 - △ 逻辑式(logic):唯一需要你新建直觉的一支。它不关心「怎么一步步算出来」,它关心「什么条件能成立」。Verse 里那些最让人愣住的设计全在这儿:单个
=是一次可能失败的相等判断而不是赋值;if承接的不是 true / false 两个值,而是「这条路走不走得通」;for遍历的是一个表达式的整个「成功空间」。蓝图里找不到对应物——这是你唯一要新学的味觉。
所以官方给 Verse 的定位是函数式逻辑语言(functional logic language):前两个词说明它的骨架,而命令式那一面之所以保留,是为了让写玩法的人还能用最自然的方式表达「先后顺序」。你会发现越靠近玩法层,Verse 越像你熟悉的样子;越往下走,函数式和逻辑式的性格越明显。
二、Verse Calculus:剥到只剩骨架的那台裸机
2023 年,Simon Peyton Jones、Tim Sweeney、Lennart Augustsson 等作者在函数式编程的顶级会议 ICFP 上发表了论文《The Verse Calculus: a core calculus for deterministic functional logic programming》。工业界为自家脚本语言写形式化论文本就少见,更少见的是这份作者名单:语言的老板和函数式编程的宗师并排署名。(Peyton Jones 于 2021 年 12 月以 Engineering Fellow 的身份加入 Epic 参与语言设计。)
这篇论文做的事可以一句话讲清:Verse 演算就是 Verse 剥到只剩骨架后的「最小内核」。把所有只是让代码写起来顺手的便捷写法全部剥掉,剩下的就是这台裸机;语言里发生的一切,最终都能还原到这台裸机的几条规则上。
内核里有三样东西,每样都对应你在正课里会遇到的一条「怪规矩」:
- ◇ 变量靠合一(unification)绑定。变量不是「一个装值的盒子」,而是「一个待解的未知数」,程序运行有点像解方程——让等式两边成立。这就是为什么单独的
=是「可失败的相等」,而把值塞进变量那件事(蓝图里的 Set 节点)要另外写作set。 - △ 一段计算可以吐出好几个值。结果不一定只有一个,可能是一串候选值组成的「选择空间」。而
for(蓝图里的 ForEach Loop)本质上就是把这一串成功的值挨个走一遍。 - ▢ 整门语言是确定性的。同一个程序永远只跑出同一种结果,不会因为内部求值顺序不同而今天这样、明天那样。对一个要把上千段逻辑塞进同一个世界的引擎来说,这一条不是学术洁癖,是能不能睡着觉的问题。
不必去读论文才能写 Verse。但知道这台裸机存在,你就明白后面那些规矩不是随手定的——它们背后有一群写了几十年编译器、证明了几十年定理的人在做取舍。
三、事务性内存:世界要么整步前进,要么原地不动
Epic 对 Verse 有一句很浓缩的说法:它「把 C++ 事务化」(transactionalizes C++)。「事务」这个词借自数据库:一段逻辑要么整体生效,要么像从没发生过一样整体回滚,不存在改了一半的中间状态。
换成蓝图视角:可以想象成 Verse 先在一张看不见的「影子图」上把这段逻辑试连、试跑一遍,只有整段都顺利走通,改动才真正落到游戏世界;中途只要卡住一步,就当这张影子图从没连过,世界原封不动。
为什么这件事在多人在线世界里是刚需?单机里出现「金币扣了、道具没发」,大不了玩家重开一局。而在一个不停机、许多人共处的世界里,半成品状态会立刻被别人看见,并被当成真相继续往下算——他基于错误的库存做了交易,交易又触发了别人的逻辑。错误在联机世界里不是停在原地,它会传染。事务性就是把这条传染链从语言层面掐断:任何一段逻辑,对世界的影响都是原子的,要么全有,要么全无。
四、结构化并发:每只风筝都得拴在柱子上
另一个卖点是并发。你在蓝图里其实早就用过异步的东西:Delay、Timeline、各种带时钟图标的 Latent 节点。它们的共同点是「拉出去之后就跑在你看不见的地方」,而收尾——比如玩家中途退出时把它停掉——基本靠你自己记得。
结构化并发要求的正好是这件事被记住:每一条被开出去的执行线,都必须有明确的归属和结束条件;当它的父任务结束时,它不会变成没人管的孤儿继续跑下去。Verse 把这套东西直接内建成语法——spawn(放出去自己跑)、race(几条线赛跑,谁先完成就采用谁)、sync(几条线一起跑,全到齐再继续),第 24 课会逐个拆开。
比喻一下:蓝图里开一个 Delay,像是放一只风筝出去,线握不握得住全看你;结构化并发则是规定了每只风筝必须拴在某根柱子上,柱子拔了,风筝跟着收回来。在一个玩家随时退出、对局随时结束、内容随时热更新的世界里,没人收尾的异步任务就是内存泄漏和幽灵逻辑的来源——「那个已经离场的玩家的倒计时,五分钟后突然给全场发了条广播」这种事,你一定不想调试。
把三节串起来:混血给了 Verse 表达力,事务性给了它安全,结构化并发给了它时间维度上的秩序。这三样凑齐,才敢有 UE6 里那句「从零基于 Verse 构建 Scene Graph」。
五、小测一下
说 Verse 是「事务性」的,最准确的意思是?
来源与延伸
本文整理自论文专页、公开演讲与 Epic 官方新闻: