混合视觉与文本代码
摘要
本文介绍了Hybrid ClojureScript,一种允许开发者混合视觉与文本语法用于领域特定表达式的编程语言,保持了可组合性和静态推理能力。
暂无内容
查看缓存全文
缓存时间: 2026/06/25 05:15
# 混合视觉与文本代码 来源:https://arxiv.org/html/2603.15855 Leif Andersen\\institution马萨诸塞大学波士顿分校\\city波士顿\\state马萨诸塞州\\country美国 \\[email protected] Michael Ballantyne\\institution东北大学\\city波士顿\\state马萨诸塞州\\country美国 \\[email protected] Cameron Moy\\institution东北大学\\city波士顿\\state马萨诸塞州\\country美国 \\[email protected] Matthias Felleisen\\institution东北大学\\city波士顿\\state马萨诸塞州\\country美国 \\[email protected] Stephen Chang\\institution马萨诸塞大学波士顿分校\\city波士顿\\state马萨诸塞州\\country美国 \\[email protected] ###### 摘要。 主流编程语言仅支持线性文本来表达领域特定的几何概念。我们真正需要的是混合语言——允许开发者创建视觉语法结构,从而能够使用针对特定应用领域定制的文本与视觉混合语法来表达想法。这种混合必须将两种语法置于平等地位,同样重要的是,扩展后的语言不能破坏程序员惯常的工作流程。这意味着任何新的视觉语法都应是恰当的语言扩展,并能与其他语言特性组合使用。此外,这些扩展还应保持对程序的静态推理能力。本文提出**Hybrid ClojureScript**,首个此类混合编程语言。Hybrid ClojureScript允许程序员添加视觉交互语法,并将这些语法的实例嵌入到程序文本中。增强型混合IDE可以将这些嵌入的实例显示为程序员可与之交互的迷你图形界面,而其他IDE则会显示语法的文本表示。本文论证了此类可扩展机制的必要性,展示了设计的可采纳性,并讨论了在其他语言中使用该设计可能需要做的工作。 ## 1. 文本代码不够用,纯视觉代码也可能过犹不及 编程语言帮助程序员交流想法,既面向计算机也面向其他程序员。线性文本在大多数情况下足以胜任,但许多想法本质上是几何化的,更适合用视觉来表达。 ### 1.1. 背景与研究现状 可视化编程语言[11](https://arxiv.org/html/2603.15855#bib.bib11)提供了一种潜在解决方案,但许多语言要求程序的所有部分都是可视化的,尽管并非所有代码都适合以这种方式理解。此外,正如几十年的编程历史所显示的那样,开发者永远不可能完全放弃文本语言——因此任何图形语法都必须**补充**而非取代文本语法。另一个问题是,许多可视化语言不可扩展或不够“丰富”[35](https://arxiv.org/html/2603.15855#bib.bib35);也就是说,程序员无法根据领域定制图形语法。关于实时编程的大量工作[8](https://arxiv.org/html/2603.15855#bib.bib8)、[35](https://arxiv.org/html/2603.15855#bib.bib35)、[63](https://arxiv.org/html/2603.15855#bib.bib63)、[67](https://arxiv.org/html/2603.15855#bib.bib67)、[73](https://arxiv.org/html/2603.15855#bib.bib73)]在推动代码超越静态文本、进入视觉世界方面取得了很大进展。这些系统通常允许通过程序运行时行为的反馈来以视觉方式编辑代码(从而摆脱了“静态文本”的“静态”和“文本”两方面)。虽然这开启了大量新的应用,但也带来了过度动态代码众所周知的权衡——例如在安全性或静态推理能力方面——详见关于在JavaScript中使用`eval`的广泛警告[16](https://arxiv.org/html/2603.15855#bib.bib16)、[65](https://arxiv.org/html/2603.15855#bib.bib65)]。 本文是作者前期工作[3](https://arxiv.org/html/2603.15855#bib.bib3)的重大修订与扩展,提出了一种新颖的解决方案:设计并实现了一种混合视觉-文本语言——**Hybrid ClojureScript**——它既可扩展又保留了静态推理能力。该语言的关键特性在于,程序员可以通过混合文本和**视觉交互语法**(VIsx,读作“vizzix”)来构建代码。正如其名,VIsx不仅仅是文本的可视化,它还具有交互性。也就是说,通过点击或其他GUI手势编辑VIsx会改变代码。同时,VIsx也是一种语法,其文本表示始终可用于编辑(例如在纯文本编辑器中),并且其GUI会根据文本的更改而更新。此外,每个VIsx都是混合语言的扩展,这使得能够创建自定义结构,直观地表达特定问题领域的概念。这些扩展是“语言层面的”,意味着它们成为语言本身的正式组成部分,不需要外部工具或在语言中享有特殊地位。此类扩展还可以与其他语法和语言结构(包括抽象机制)组合使用。它们可以与同一文件中的其他定义一起定义和使用,甚至可以用来定义其他VIsx,也可以打包成库供其他程序员共享和使用。它们还可以对程序的许多不同部分进行抽象,而不仅仅是表达式或语句。最后,由于这些扩展是语言层面的,现有的重构和分析工具对于使用了可视化代码元素的程序仍然有效。 过去几十年来,这种可扩展性主要由Scheme宏系统[18](https://arxiv.org/html/2603.15855#bib.bib18)]以及Racket语言创建语言层次结构的能力[23](https://arxiv.org/html/2603.15855#bib.bib23)、[4](https://arxiv.org/html/2603.15855#bib.bib4)]率先探索,但此类抽象能力正变得越来越主流,例如在现代语言的宏系统中,如Rhombus[26](https://arxiv.org/html/2603.15855#bib.bib26)]、Rust[39](https://arxiv.org/html/2603.15855#bib.bib39)]、Scala 3[72](https://arxiv.org/html/2603.15855#bib.bib72)]、Julia[70](https://arxiv.org/html/2603.15855#bib.bib70)]和Elixir[69](https://arxiv.org/html/2603.15855#bib.bib69)]。此类系统的一个独特特性是,宏的展开可以产生更多宏调用、宏定义,甚至一系列宏、函数和其他定义。我们工作的一个贡献是将这种“层次结构”扩展到代码编辑阶段,具体形式是图形语法扩展。具体来说,我们创建了**Hybrid ClojureScript**,它将图形语法能力添加到可扩展语言Clojure中,其中每个VIsx本身就是一个恰当的语言扩展。拥有此能力意味着VIsx展开的结果可以是其他VIsx定义。这使得许多用例成为可能,例如第7.4节中的元VIsx,这在其他图形语法系统中是无法实现的。一个复杂的问题是,在每个展开阶段可能会运行任意代码来产生该阶段的输出。这些任意代码甚至可以由宏输出的一部分定义,然后由另一部分使用。为了保证定义(包括生成的宏和函数定义)在展开过程中能适时可用,已有研究[25](https://arxiv.org/html/2603.15855#bib.bib25)]表明代码执行应分为不同的代码阶段,例如“编辑时”(VIsx代码运行时)、“编译时”和“运行时”。例如,仅在展开期间使用的代码不应在运行时再次运行。而依赖于另一个宏的宏需要在该宏之后展开。在宏生成宏的可能性下,不同的阶段是必要的,以限制VIsx实例可以访问的动态信息量,从而保持某些静态属性(如绑定和卫生性),并能够实现扩展的组合性。相比之下,其他可扩展系统(无论是图形还是非图形)通常只允许在有限的程序上下文中展开,大多数不能发出其他定义,并且通常只有固定数量的展开阶段(通常是一个)。这意味着它们无法实现我们评估中的所有示例。 我们对恰当语言扩展的重视,以及这些扩展所需的不同代码阶段,是我们工作与其他图形语法努力的主要区别。根据Horowitz和Heer[35](https://arxiv.org/html/2603.15855#bib.bib35)]提出的标准——他们建议非文本编程系统应“实时、丰富且可组合”——Hybrid ClojureScript优先考虑“丰富性”,即创建领域特定图形语法的能力,但如前所述,我们的扩展超越了其他项目的能力。为此设计选择的权衡是,虽然我们的“丰富”扩展天然是“可组合”的,但“实时性”变得更加复杂。更具体地说,维持不同的代码阶段意味着并非所有VIsx都是实时的。相反,程序员可以有意识地限制扩展可以访问的动态信息量,以保留更多的静态推理能力。然而,程序员也可以编写具有实时反馈循环的VIsx,因此使用Hybrid ClojureScript,程序员可以创建那些位于完全静态到完全实时之间的混合程序。 ### 1.2. 贡献与前期出版物的关系 我们利用第一个Racket[28](https://arxiv.org/html/2603.15855#bib.bib28)]混合语言原型的经验,实现了第二个原型——**Hybrid ClojureScript**——它基于ClojureScript[45](https://arxiv.org/html/2603.15855#bib.bib45)],一种有一定商业用途的函数式语言。除了能够在新的生态系统中进一步评估我们之前的见解和想法之外,**第二个实现贡献了一个额外的关键智力见解**,即未来的混合语言应该如何构建:混合语言的构建应该依赖**保留模式**的图形用户系统[37](https://arxiv.org/html/2603.15855#bib.bib37)]来渲染可视化,而不是**即时模式**[58](https://arxiv.org/html/2603.15855#bib.bib58)]。 更详细地说,Racket的混合能力使用了该语言的GUI框架[27](https://arxiv.org/html/2603.15855#bib.bib27)],这也是其主要IDE DrRacket[24](https://arxiv.org/html/2603.15855#bib.bib24)]的基础。具体来说,Hybrid Racket的VIsx能力必须依赖于canvas类,这是一个即时GUI元素[58](https://arxiv.org/html/2603.15855#bib.bib58)],意味着它会立即在给定的绘图上下文中指定位置绘制图形。但为了允许VIsx拥有文本表示,它不能是即时渲染的,因为它并不总是能访问绘图上下文。因此,其API必须以保留模式运行。结果,最初的Racket版本不得不重新实现canvas类以及其他所有小部件(按钮、下拉菜单等)的保留版本。这对VIsx用户的影响是严重的:如果他们的应用程序带有使用Racket普通小部件的GUI,并且他们希望在代码中以VIsx形式表达相同的几何想法,他们必须使用团队新的保留小部件(远没有现有小部件精致,且存在严重的性能问题)重新实现这个GUI。换句话说,开发者必须用两个独立的库重复实现同一个GUI。语言实现者也深受其害,因为他们现在必须维护两个独立的GUI库并保持同步。简而言之,Racket的图形用户系统成了创建混合语言的重大障碍。 相比之下,某些语言中的GUI是通过DOM(一种保留模式图形系统)创建和操作的。如果至少有一个IDE使用相同的GUI系统,团队可以轻松修改这个IDE,使其能够将VIsx代码显示为文本或嵌入的迷你GUI,甚至可以并排显示,从而消除了对两个独立GUI库的需求。简而言之,它可以创建混合语言系统。实现第二个混合语言的经验还贡献了评估混合语言的另一种方式。Andersen等人最初的工作侧重于**有用性**——展示图形化VIsx确实比文本代码更好地表达某些概念——而混合语言还应该是**可采纳的**——意味着它应尽可能保留程序员惯常的工作流程。可采纳性的重要一步是基于用户已经熟悉的现有通用语言创建混合语言,而不是强迫用户学习新的临时专用语言。相关的第二步是维护与程序员熟悉工具(如IDE)和库的兼容性。程序员出了名地挑剔他们偏好的工具,不会轻易切换到新工具。可采纳性的第三个方面是允许程序员在定义和使用VIsx时使用现有库,这是Racket初步实现所不允许的。沿着这些思路,Hybrid ClojureScript是现有ClojureScript语言的扩展。它还附带了一个基于CodeMirror的混合IDE,其基本编辑UI已为许多程序员所熟悉,特别是那些使用基于浏览器的IDE的用户(例如GitHub、CodePen、JSFiddle等用户)。最后,如前所述,Hybrid ClojureScript用户可以使用标准DOM API创建和操作GUI组件,DOM不仅可以在浏览器中使用,还可以在现代IDE(如Visual Studio Code)甚至某些原生操作系统(如Android)中使用。这意味着程序员还可以使用许多熟悉的基于DOM的GUI库,如React、Angular和Vue.js。所有这些都显著提高了我们新混合语言的可采纳性。 为了强调这一点,本文提出了两项评估。首先,它将新的混合语言与原始版本[3](https://arxiv.org/html/2603.15855#bib.bib3)]进行了比较(包括移植所有先前的示例),揭示了关键差异。其次,它新增了一项针对新语言的独立评估,侧重于可采纳性,该评估本身包含两个部分: - •该语言如何影响特定的程序员工作流程行为;以及 - •程序员如何使用现有库实现图形语法。 最终得到一种更适合帮助程序员在适当的时候以视觉方式表达代码的编程语言。作者强烈建议熟悉原论文的读者研读这些新内容。 ### 1.3. 第一个几何示例 本节的剩余部分将通过一个示例介绍Hybrid ClojureScript以及视觉交互语法(VIsx)。为了展示VIsx的有用性,考虑一个棋盘游戏Tsuro的软件实现¹¹¹。https://en.wikipedia.org/wiki/Tsuro 在游戏中,玩家轮流放置包含四条路径段的正方形图块,每条路径段连接正方形的两条边。当放置一个图块时,每个玩家触碰新图块的游戏棋子会沿着新延伸的路径尽可能远地移动。如果此移动迫使游戏棋子离开棋盘,则该玩家被淘汰。最后存活的玩家获胜。 参见图1的说明。 **图1. 一个Tsuro图块的VIsx** 现在想象一个程序员希望为该游戏编写单元测试。如果代码使用支持VIsx的编程语言编写,测试者可以导入Tsuro图块代码的图形表示。这种渲染...
相似文章
依赖类型的 Clojure 领域特定语言,带有与 Lean4 兼容的内核
Ansatz 是一个 Clojure 库,实现了 Lean 4 的归纳构造演算内核,使 Clojure 程序员能够编写依赖类型的、经过验证的代码,这些代码的证明与 Mathlib 兼容,并能编译为 JVM 字节码。
空间语言:二维代码编写
本文探讨了二维代码编写的概念,通过垂直链式调用和三目中缀运算符简化某些表达式,并以鸡舍门控制器等实际案例为例。
Clojure 速度几乎媲美 C(需借助一些优化)
本文详细介绍了 Clojure 如何借助 JVM 的 Vector API 和精心优化,在 3D 压力测试中达到接近 C 的帧率(仅差 20%),展示了动态语言在热循环中也能接近底层性能。
@freeCodeCamp: Clojure 是一种函数式编程语言,能改变你对编写代码的思考方式。在这份互动指南…
一份互动指南,通过动画代码回放和动手练习介绍 Clojure 编程,涵盖函数、不可变数据、递归等。
Jolt:使用Chez Scheme实现的Clojure编译器
Jolt是一个自托管的Clojure实现,可编译为Scheme(本地使用Chez,通过Gambit支持JavaScript),提供独立二进制文件、真正的并发性以及完整的Clojure语义,无需JVM。