Functional Programmers need to take a look at Zig

Functional Programmers need to take a look at Zig

函数式程序员需要关注一下 Zig

Functional Programmers need to take a look at Zig. I’ve been tinkering around with Zig to explore what’s possible with comptime. 函数式程序员需要关注一下 Zig。我一直在折腾 Zig,以探索 comptime(编译期执行)所能带来的可能性。

Whenever I evaluate a new language I use three axes: How well can I express my ideas in this language. Or in other words, how easy is it for me to express the domain of the program. This is a test on how much noise is applied to the ideas I want to express in the program. Noise is anything that must be written for the program to function that is not relevant to the domain. For example, the canonical example of noise is the need to do manual memory management. We must allocate memory for the program to run, but this is orthogonal to the program’s domain; its an implementation detail. 每当我评估一门新语言时,我都会使用三个维度:我在这门语言中表达想法的能力如何?换句话说,我表达程序领域逻辑的难易程度如何?这实际上是在测试我想要表达的想法中掺杂了多少“噪音”。噪音是指为了让程序运行而必须编写、但与领域逻辑无关的任何内容。例如,噪音的典型例子就是手动内存管理。为了让程序运行,我们必须分配内存,但这与程序的领域逻辑是正交的;它只是一个实现细节。

What facilities does the language provide me to create correct-by-construction systems and how easily can I program the type-system. This is essentially a test on how well I can program the language itself or how well I can create a deep embedding. 这门语言提供了哪些工具来让我构建“构造即正确”(correct-by-construction)的系统?我对类型系统的编程有多容易?这本质上是在测试我编程语言本身的能力,或者说我创建深度嵌入(deep embedding)的能力。

What is the mean-time to a surprise. In the study of vacuum systems (think outer space) there is a concept called the mean-free path length or just mean-free path. The mean-free path of a vacuum system is the average distance a particle can travel in the system without experiencing a collision, it is essentially a metric of how good the vacuum is. When I apply this concept to programming languages I think of it as “How much code can I write before my implementation differs from my understanding of the system I am implementing”. This is why I frame this metric as a “surprise”; its “how many lines of code can I write until I experience a surprise”. And a surprise is a delta between what I think I’ve implemented and what I’ve actually implemented. 什么是“惊喜平均时间”(mean-time to a surprise)?在真空系统(想象外太空)的研究中,有一个概念叫“平均自由程”(mean-free path)。真空系统的平均自由程是指粒子在系统中发生碰撞前所能行进的平均距离,它本质上是衡量真空度好坏的指标。当我把这个概念应用到编程语言时,我将其理解为:“在我的实现与我对系统的理解产生偏差之前,我能写多少代码?”这就是我将其称为“惊喜”的原因;它是指“我能写多少行代码才会遇到一个惊喜”。而“惊喜”就是我以为我实现了什么,与我实际实现了什么之间的差值。

Enter Zig. I’m interested in Zig for a few reasons. First, I suspect that comptime is a simpler and more flexible system to achieve a lot of the type-system programming I’ve seen in the Haskell-verse and I’ve done enough Haskell (over 10 years) that programming the type system is now a hard requirement for me to take any language seriously. 接下来是 Zig。我对 Zig 感兴趣有几个原因。首先,我怀疑 comptime 是一种更简单、更灵活的系统,能够实现我在 Haskell 生态中看到的许多类型系统编程功能。我已经写了足够多的 Haskell(超过 10 年),以至于“对类型系统进行编程”现在已成为我认真对待任何语言的硬性要求。

Second, I am desperately trying to avoid writing a functional systems language. This is probably a blog post in its own right but the programming language industry has not grokked the meaning of monads. Monads are not some kind of obscure math-y thing that only the big brains think are necessary. No, instead monads are a fundamental abstract algebraic description of imperative programming as a computational context. They allow a programming language to not have a built-in notion of time (among other things). So if I want an imperative programming language I can implement MonadCont (the continuation monad), if I want a logic programming language I can implement LogicT (a monad that has non-deterministic semantics and backtracking). Not having a built-in notion of time means that my language is de-facto more expressive, allows users to mold the language to their needs, and improves the optimization ceiling compilers for that language can achieve. 其次,我极力避免编写一门“函数式系统语言”。这本身可能就是一篇博客文章的主题,但编程语言行业至今仍未真正理解单子(Monad)的含义。单子并不是什么只有天才才觉得必要的晦涩数学概念。相反,单子是对作为计算上下文的命令式编程的一种基础抽象代数描述。它们允许编程语言不具备内置的“时间”概念(以及其他特性)。因此,如果我想要一门命令式编程语言,我可以实现 MonadCont(延续单子);如果我想要一门逻辑编程语言,我可以实现 LogicT(一种具有非确定性语义和回溯功能的单子)。不具备内置的时间概念意味着我的语言实际上更具表现力,允许用户根据自己的需求塑造语言,并提高了该语言编译器所能达到的优化上限。

So how does this connect with systems programming? Well, I’ve been radicalized. I’ve learned enough performance-oriented programming to be dissatisfied with the common functional languages (Haskell, OCaml, Common Lisp/Clojure, Scheme) because each of these languages are predicated on the existence of garbage collection and heaps. I think we are at the tail end of a large scale experiment with garbage collection. We can now look back on the last 30 years and conclude that garbage collection does communicate immense value by reducing noise, but the tradeoff is that the one ends up with a forest of pointers into the heap and that will always create a performance ceiling for the program and language implementation. 那么这与系统编程有什么联系呢?好吧,我的观点已经变得激进。我学习了足够多的面向性能的编程知识,以至于对常见的函数式语言(Haskell、OCaml、Common Lisp/Clojure、Scheme)感到不满,因为这些语言都建立在垃圾回收(GC)和堆内存存在的基础上。我认为我们正处于一场关于垃圾回收的大规模实验的尾声。回顾过去 30 年,我们可以得出结论:垃圾回收通过减少噪音确实带来了巨大的价值,但代价是程序最终会产生指向堆内存的指针森林,这永远会为程序和语言实现设定一个性能上限。

To exacerbate matters, I think there is a cognitive risk to garbage collection. Garbage collection makes it too easy to not think about or care about the underlying machine and runtime system. This has created a generation of developers who never gained or have lost the knowledge of how programs actually execute on a computational machine. Or to use less flowery language, just look at the era of software that garbage collectors have ushered in. Programs are bloated, slow, and wasteful compared to the literal super-computers that are running them. Surely we can do better. 更糟糕的是,我认为垃圾回收存在认知风险。垃圾回收让人太容易不去思考或关心底层机器和运行时系统。这造就了一代开发者,他们从未获得或已经失去了关于程序如何在计算机器上实际执行的知识。或者用更直白的话说,看看垃圾回收器所带来的软件时代吧。与运行它们的超级计算机相比,现在的程序臃肿、缓慢且浪费。我们肯定可以做得更好。

Furthermore, I think the value proposition of garbage collectors has changed. The first garbage collector was innovated in LISP in 1957, but once they gained prominence in 1995 due to Java they proliferated, and for good reason. However, the machines of 2026 are much different than the machines of 1995 (but our languages aren’t ). Since 1995, compute on a CPU has grown something like 10,000 times faster while memory access timing has lagged. That was not the case in 1995. In 1995 these were roughly comparable. So we are in a situation where we are using languages designed for the machines of yesteryear that do not consider the machines of today. 此外,我认为垃圾回收器的价值主张已经发生了变化。第一个垃圾回收器于 1957 年在 LISP 中诞生,但在 1995 年因 Java 而声名鹊起后,它们便迅速普及,这不无道理。然而,2026 年的机器与 1995 年的机器大不相同(但我们的语言却没有变)。自 1995 年以来,CPU 的计算能力增长了约 10,000 倍,而内存访问速度却滞后了。1995 年并非如此,当时这两者大致相当。因此,我们现在的处境是:我们正在使用为过去机器设计的语言,而这些语言并未考虑当今的机器。

As an industry we (largely) have stopped innovating on new languages. I once saw a talk by Steven Diehl that asked Where the next Programming Language will come from? that beautifully described the sad state of things. His main point is that the incentives for programming language innovation are at best misaligned and at worst non-existent. He states that we can assume there are three groups of people that are capable of innovation: Academics, Industry, and Hobbyists. But academics have no incentive to do the real-world engineering required to make a viable programming language, and any academics who decide to try are committing career suicide. Industry cannot fund any long-term projects (due to its culture of shareholder-value maximization) and are tied into sticky network effects. Hobbyists (generally) don’t have the time nor the economic means to make something real; which takes decades of full time work to accomplish. And so we are stuck with a local maxima. Okay now back to Zig. I’m bullish on Zig beca 作为一个行业,我们(很大程度上)已经停止了对新语言的创新。我曾看过 Steven Diehl 的一场演讲,题目是《下一门编程语言将从何而来?》,它精彩地描述了这种令人悲哀的现状。他的核心观点是,编程语言创新的激励机制往好了说是错位的,往坏了说根本不存在。他指出,我们可以假设有三类人有能力进行创新:学术界、工业界和业余爱好者。但学术界没有动力去进行开发可行编程语言所需的现实工程工作,任何决定尝试的学者都是在进行职业自杀。工业界无法资助任何长期项目(由于其股东价值最大化的文化),且被粘性的网络效应所束缚。业余爱好者(通常)没有时间也没有经济能力去创造真正的东西,而这需要数十年的全职工作才能完成。因此,我们被困在了一个局部最优解中。好了,回到 Zig。我看好 Zig,因为……