跳到正文
Hacker News· chrispaig3·· 8 天前AI 评分22

Axiom 0.7.8:用 Axiom 自身编写的函数式系统编程语言

Show HN: Axiom: The Functional Systems Langauge

AI 导读

Axiom 0.7.8 发布,这是一门开源函数式系统编程语言,编译器本身由超过 119,000 行 Axiom 代码写成,可从提交的 LLVM IR 经 llc 与 C 链接器重建并校验两代字节一致。它通过类型与效果系统在编译期捕获遗漏分支和 I/O 副作用,直接编译为含分配器与系统调用的原生二进制,无 VM 和 GC,已为 macOS 与 Linux arm64 提供预编译版本。

正文 · AI 翻译

Axiom 0.7.8 开源。用 Axiom 构建。

函数式系统语言

用强大的类型表达你的想法。在编译期捕获遗漏的分支并检查副作用。交付一个无需 VM 或垃圾回收器的原生二进制文件。

献给那些在意代码如何抵达机器的人。

01 / 设计即表达为你的想法建模的类型。02 / 该明确处必明确编译器检查的副作用。03 / 原生从始至终LLVM。直达机器。

看它实际运行

一个小程序。全貌尽显。

编写它。运行它。破坏它。
看编译器如何捕获变化之处。

shapes.ax — 从源码到可执行文件

一段录制的终端会话:一个和类型:三种形状,每种都带命名字段。area 承诺它不执行任何 I/O。编译器会要求它做到这一点。report 会打印,所以它声明了:effect(io)。一步编译并运行。无需构建文件。$ axiom run shapes.ax 添加第四种形状,别的什么都不改。area 中的 match 不再覆盖所有形状。编译器会指出它,以及缺失的分支。$ axiom check shapes.ax 处理六边形,并报告一个。$ axiom run shapes.ax 一个原生可执行文件,其分配器和系统调用都在其中。$ axiom build shapes.ax -o shapes $ ./shapes

你的下一个原生二进制文件从这里开始。

为 macOS 和 Linux arm64 预构建。安装及其他目标平台

curl -fsSL https://raw.githubusercontent.com/chrispaig3/axiom/trunk/scripts/install.sh | bash

早期阶段的语言。真正的编译器。看看今天已就绪的功能。

为什么选择 Axiom

小巧的语言。强大的能力。

函数式编程的表达力,加上通往原生代码的直接路径。每一个设计选择都给你实实在在可用的东西。

  • 交付二进制文件。就这样。

    你的程序编译为原生可执行文件,包含其分配器并直接调用内核。无需配置 VM。无需调优垃圾回收器。

    scripts/check-freestanding.sh
  • 让副作用显式化。

    将计算与 I/O 分离。编译器推断副作用,检查 restrict(no-io),并要求执行 I/O 的函数声明它。

    ;@axiom:restrict(no-io)
  • 找到问题。继续前进。

    获得精确的位置、稳定的错误代码,而且往往还有你的工具可以应用的修复方案。axiom explain 为 108 个错误代码中的每一个都设有页面。

    axiom explain AX3005
  • 为你而建。也为你的智能体而建。

    统一的语法让代码生成可预测。结构化诊断、精确的范围和稳定的符号 ID,让你的工具获得与你审查其工作时所用相同的事实。

    --diagnostic-format=ai
  • 阅读编译器。用 Axiom 编写。

    编译器是超过 119,000 行的 Axiom 代码。一次干净的检出会用 llc 和 C 链接器从提交的 LLVM IR 重新构建它,并且除非两代产物逐字节相同,否则会停止。

    scripts/bootstrap-from-seed.sh
  • 把 Rust 也带上。

    让有用的 Rust 代码触手可及。在 extern 块中声明函数;--crate 会构建并链接该 crate。当 Rust 值的最后一个 Axiom 引用消失时,它会被丢弃。

    axiom build --crate DIR

导览

感受一下这门语言。

十个可运行的程序,从你的第一个数据类型到调用 Rust。探索代码,跟随注释,看看每个程序究竟打印出什么。

01/14 · parcels.ax

货运状态报告

带命名字段的和类型,穷尽匹配。Option 是内置的,所以缺失的值是一种类型,而不是 null。

  • L6构造函数可以携带命名字段。
  • L18alert 返回 Option String,因为有些包裹无需处理。
  • L31optUnwrapOr 在没有值的地方提供默认值。
  • L33{id:<9} 填充到九列。格式字符串是编译的,而非在运行时解释。

parcels.ax

(import IO)
(import Err)

(data Parcel
  (Ordered)
  (InTransit { carrier : String, days : Int })
  (Held { why : String })
  (Delivered))

(:: status (-> Parcel String))
(fn (status p)
  (match p
    ((Ordered) "packing")
    ((InTransit carrier days) (format "{carrier}, {days} days out"))
    ((Held why) (format "held at {why}"))
    ((Delivered) "delivered")))

(:: alert (-> Parcel (Option String)))
(fn (alert p)
  (match p
    ((Ordered) (Some "not shipped yet"))
    ((InTransit _ _) None)
    ((Held why) (Some (format "call about {why}")))
    ((Delivered) None)))

(:: row (-> String Parcel Int))
;@axiom:effect(io)
(fn (row id p)
  (let (
    (s (status p))
    (a (optUnwrapOr (alert p) "-"))
  )
    (println "{id:<9}{s:<22}{a}")))

(:: main Int)
;@axiom:effect(io)
(fn (main)
  {
    (println "parcel   status                action")
    (row "AX-1041" Ordered)
    (row "AX-1042" (InTransit "DHL" 2))
    (row "AX-1043" (Held "customs"))
    (row "AX-1044" Delivered)
    0
  })

axiom run parcels.ax

parcel   status                action
AX-1041  packing               not shipped yet
AX-1042  DHL, 2 days out       -
AX-1043  held at customs       call about customs
AX-1044  delivered             -

性能

小体积二进制。实测性能。

在这个 Collatz 基准测试中,Axiom 的运行时间与 C 和 Rust 相差仅几毫秒,二进制体积也接近 C。单一工作负载,单台机器,源码与方法均已提供,可供复现。

运行时间三者均在 5 毫秒以内3,000,000 个 Collatz 序列 · hyperfine 取 20 次最佳,交错运行

Axiom0.443 s

Rust0.448 s

C0.444 s

三者完成时间彼此相差均在五毫秒以内。Axiom 生成 LLVM IR,因此一个只含算术和分支的循环会得到与另外两者相同的机器码。

编译为原生二进制Axiom 最慢,慢 49 毫秒单文件,冷启动 · hyperfine 取 15 次最佳,交错运行

Axiom0.166 s

Rust0.117 s

C0.151 s

Axiom 是三者中最慢的,比 rustc 慢四十九毫秒,为 1.42 倍;比 clang 慢十五毫秒,为 1.10 倍。之所以公布,是因为这就是实测结果,由源码旁的脚本测得。

二进制体积比 Rust 小 13 倍,比 C 大 7%磁盘上的可执行文件

Axiom35,784 B

Rust469,608 B

C33,432 B

比 Rust 二进制小十三倍,比 C 大约百分之七,且内部完全没有 C 运行时。

未定义符号Axiom 为 0,Rust 为 70,C 为 1nm -u <binary> | wc -l

Axiom0

Rust70

C1

整个程序都在文件里。加载时无需解析任何东西,因为已没有什么需要解析。

Apple M1,macOS 27.0.1,darwin-aarch64 · Axiom 0.7.8 · rustc 1.98.1 · clang 23.1.2 · 使用 hyperfine 1.20.0 计时。三者均打印 428343467。

如何测量,以及图表背后的表格

对 1..3,000,000 的 Collatz 步数求和并打印。有符号 64 位整数,无内存分配,热循环中无库调用。每个数字是其各次运行中的最佳值,而非平均值:干扰只会让运行变慢,因此最小值是最接近成本本身的估计。

各次运行是交错进行的,依次对每个二进制各重复一次,而这一修正改变了结果。第一轮将每个二进制分块运行,使 Axiom 落后 Rust 1.6 倍。那是一种假象:中途启动的后台构建会拖累它所落在的那个块。交替运行让每个二进制受到相同的干扰,于是三者彼此重合。

这三个程序都在仓库的 web/bench/ 中,旁边的 run-bench.sh 会生成此表的每一个单元格,因此可以重新运行,而不必仅凭信任接受。Go 和 Haskell 缺席,是因为机器上没有这两者的工具链,而本项目只公布它实测过的数字。一个微基准测试说明不了分配密集型工作的情况,scripts/bench-datastructures.sh 对此单独测量,结果没那么好看。

axiom build --input collatz.ax --output out-axiom
rustc -O collatz.rs -o out-rust
clang -O2 collatz.c -o out-c
Axiom、Rust 和 C 中同一 Collatz 工作负载的运行时间、编译时间、二进制大小和未定义符号数量。
测量项AxiomRustC
运行时间3,000,000 个 Collatz 序列 · hyperfine 取 20 次最佳,交错运行0.443 s0.448 s0.444 s
编译为原生二进制单文件,冷启动 · hyperfine 取 15 次最佳,交错运行0.166 s0.117 s0.151 s
二进制大小磁盘上的可执行文件35,784 B469,608 B33,432 B
未定义符号nm -u <binary> | wc -l0701

对比

一组不同的取舍。

函数式类型、显式效应和原生输出集于一门语言。看看 Axiom 的选择与 Rust、Go 和 Haskell 相比如何。

AxiomRustGoHaskell

内存Bump 分配、引用计数,以及在你选择时机时使用区域。没有追踪式收集器,没有借用检查器。所有权与借用追踪式 GC追踪式 GC

二进制内部你的代码、它的分配器和原始系统调用。不调用任何 C 库函数。std 链接 C 库GC 和调度器运行时GHC 运行时系统

副作用按函数推断;用编译器检查的标签声明或限制。不追踪不追踪在类型中手动追踪

宏在类型检查前重写程序树;卫生宏。Token 流无Template Haskell

构建与运行axiom run f.ax:一步完成,无需构建文件。cargogo buildcabal 或 stack

开始使用

你的第一个原生二进制从这里开始。

Axiom 需要来自 LLVM 的 llc 和一个用于最终链接的 C 编译器。编译器本身用 Axiom 编写,因此无需先安装其他工具链。

  1. 安装 LLVM 和 C 编译器

    xcode-select --install

    brew install llvm

    export PATH="$(brew --prefix llvm)/bin:$PATH"

    Command Line Tools 提供用于最终链接的 C 编译器;Homebrew 的 LLVM 提供 llc,它不在默认路径中。

  2. 安装 Axiom

    有预构建归档时使用预构建归档;否则从提交的种子构建。

    curl -fsSL https://raw.githubusercontent.com/chrispaig3/axiom/trunk/scripts/install.sh | bash

    export PATH="$HOME/.axiom/bin:$PATH"

    适用于 arm64 上的 macOS 和 Linux。它会验证归档的 SHA-256,然后在新编译器替换任何内容之前,构建并运行一个导入标准库的程序,并且它只会替换自己创建的安装。

  3. 创建项目并运行

    axiom new 写入一个程序和一个 axiom.pkg 清单。在项目内,run 和 build 无需文件名。

    axiom new hello && cd hello && axiom run

    hello/Main.ax

    (import IO)
    
    (:: main Int)
    ;@axiom:effect(io)
    (fn (main)
      {
        (println "Hello from Axiom! 🚀")
        0
      })
    

    axiom run

    Hello from Axiom! 🚀
    

你最常用的命令

axiom check
类型检查并验证每个效应声明,不生成代码
axiom build
一个原生可执行文件,以项目命名
axiom test
每个名称以 test 开头的函数
axiom fmt
唯一规范布局
axiom explain AX3005
任何诊断代码背后的完整解释
axiom symbols Main.ax --calls
AXSYM 中的声明、效应、稳定 ID 和调用边
axiom emit-llvm Main.ax -o Main.ll
在汇编前检查 LLVM IR
axiom build Main.ax --obfuscate -o app
可选的字面量掩码和内部符号混淆
axiom repl
交互式会话,逐行编译为原生代码

设置你的编辑器 以获得高亮、跳转到定义、悬停和修复功能。

导入的模块来自入口目录、包依赖和显式搜索路径。设置 AXIOM_PATH 以添加额外模块根目录,设置 AXIOM_STDLIB 以覆盖已安装的库。模块搜索和编译器检查

运行平台

目标预构建说明
darwin-aarch64是Apple 芯片。预构建归档。
linux-aarch64是预构建归档。

--target 可从任何主机为其中任何一个发出;只有最终链接需要该目标的链接器。仅源码目标:baremetal-aarch64、darwin-x86_64、freebsd-aarch64、freebsd-x86_64、linux-x86_64、windows-aarch64、windows-x86_64。--target 为它们发出,且 CI 不在那里运行测试组。此处“supported”的含义。

裸机 AArch64 使用由板卡定义的平台接缝和可选的 QEMU 冒烟运行。编译器不在 Windows 上运行:从 Linux 或 macOS 交叉编译到它。嵌入式目标

状态

了解哪些已就绪。看看接下来是什么。

Axiom 是 0.x:可供探索,仍在演进。从一个工具、一个实验或一次贡献开始。用这张状态图来决定它适合哪里;这些行反映项目经过测试的实现状态。

完成

  • 函数与类型完成柯里化签名、刚性类型变量、精确返回类型。
  • ADT / 数据类型完成带位置字段或命名字段的和类型。
  • 模式匹配(match)完成嵌套、穷尽,在每个函数中检查。
  • 结构体完成逐字段 mut、泛型参数、自动渲染。
  • Lambda / 函数值完成闭包、部分应用、_ 洞。
  • 循环完成对范围和容器使用 for,while。
  • 系统调用完成在八个托管目标中的任何一个上,你的程序和内核之间都没有 libc。
  • 模块可见性完成只有 pub 会离开模块。
  • 自举完成它所取代的 Rust 编译器已被删除。

可用,但有明确限制

  • 效果强制;声明了两项限制两个推断缺口,均已声明:无法解析的调用被标记为不完整,且构造函数分配不计入。
  • 宏部分模板无法生成 import 或嵌套的 macro,也无法测试两个绑定器是否相同。
  • 并发语言形式,两种降级parallel、通道、一个互斥锁和任务池;taskFold 在仅标量的显式回调契约下回收每个已交付的答案。
  • 区域语法受检查的作用域,以及带逃逸规则的注解签名标量可以离开区域;类型化提升已计划。
  • 资源所有权可用文件、套接字、终端模式、通道和互斥锁在最后一个所有者放手时自行关闭或释放。
  • FFI可用通过 extern 块使用 Rust,密封所有者,以及为调用而借用的回调。
  • 标准库可用集合、密码学、可选二进制混淆、日期、JSON、网络和一个嵌入式数据库。
  • 错误处理可用;在系统调用接缝处采用Result、try 形式,以及跳过坏记录而不展开的处理程序。
  • 编辑器支持可用语言服务器加一个 tree-sitter 语法。

已移除

  • 类型类已替换由能力记录取代:接口是函数的结构体。
  • 列表已移除序列是 (Vec T)。
  • 元组已移除积是 struct,和是 data。
  • 线性类型已移除确定性回收是引用计数的职责。

尚未就绪:包索引与版本锁定、异步与调度器、能在 Windows 上运行的编译器(它可从其他平台构建 Windows 可执行文件),以及 arm64 之外的预构建归档。完整表格

常见问题

几件值得了解的事。

Axiom 可以用于生产环境吗?

对大多数团队来说还不能。它处于 0.x 阶段:核心语言(类型、匹配、结构体、循环、模块)已经完成,FFI、标准库和编辑器支持可用,宏是部分完成。状态表的每一行都指明了其背后的测试。

没有包索引,也没有绿色线程。这里有的是一个小型语言,其编译器你可以阅读,其声明都经过测试。

实现状态它有垃圾回收器吗?

没有追踪式回收器。内存来自基于 mmap 的 bump 分配器,每个堆块都带有引用计数,因此一个值在其最后一个引用消亡的瞬间就被释放,源码中无需写任何东西。文件、套接字、通道和互斥锁也是所有者:每一个在其最后一个引用消失时自行关闭或释放。当你希望在自选的时间点进行回收时,(region r body) 可一步回滚分配器。

内存模型“无 libc”究竟是什么意思?

Axiom 生成的代码及其标准库通过原始系统调用访问内核:包括打印、分配、文件、进程和套接字。如果生成的 IR 调用了 C 库函数,或可执行文件导入了 C 库函数,scripts/check-freestanding.sh 会使构建失败。

最终链接由你系统的 C 编译器完成,在 Linux 上它会加入 C 运行时的启动代码;在 macOS arm64 上,对编译后程序运行 nm -u 的结果为空。通向 Rust 的 extern 块是唯一的出口,而 no_std crate 不会通过它添加任何 C 库函数。

独立环境门禁为什么用 S 表达式?

因为程序本身已经是一棵树。没有需要记忆的运算符优先级,没有歧义的解析,宏操作的结构与编译器检查的结构相同。这种一致性也正是该语言易于被工具或智能体正确生成的原因。

编辑器方面也已覆盖:tree-sitter 语法按语法角色着色并配有彩虹括号,axiom fmt 负责布局。

我能让分发的二进制文件更难被检查吗?

选择 axiom build Main.ax --obfuscate -o app 可掩蔽字符串字面量、打乱内部函数名并剥离局部符号。全新的构建种子使每次构建都不同。该模式在优化过程中保留不透明函数条目,并省略源码级回溯表。

Crypto.Obfuscate 还会打包带有上下文绑定、拆分密钥份额和显式密钥擦除的认证加密资产。这些特性使静态检查更加困难;但检查运行中的进程的人仍可恢复嵌入的密钥和解码后的数据。静态归档不接受该编译器标志。

二进制与资产混淆工具如何检查我的程序?

axiom --diagnostic-format=ai symbols Main.ax --calls 会发出 AXSYM 声明、稳定 ID、作者标签、派生效果和调用边。Agent.Tags 读取该流,包括效果和宏声明。符号请使用 AI 格式;JSON 格式会被拒绝。

symbols --mir --axir 会公开分析与检查记录。原生构建会把经过检查、展开的语法树编译为 LLVM IR。使用 emit-llvm 查看该输出。

跟随一个程序走完编译器我必须为每个函数的效应都加注解吗?

不必。有四种效应必须通过调用链声明:effect(io)、effect(entropy)、effect(spawn) 和 effect(block)。分配与修改会被推断并报告。执行原始操作、调用 extern 或将值转换为无关引用类型的函数,需声明 effect(unsafe)。受信任的包装器会为其调用者承担该义务。restrict(...) 和 pure 会在你需要的地方添加更强的检查。

参考中的效应有 trait 或类型类吗?

它们已被能力记录取代。接口是一个持有函数的参数化结构体,而实例就是它的一个普通值,在需要的地方传递。分派即应用:没有表,没有解析规则,并且对接口泛型的函数可以调用其方法。

能力记录有包管理器吗?

一个项目就是一个 axiom.pkg 文件:axiom new 会写入一个。depend 行指定一个模块目录或一个 git URL,axiom fetch 会克隆这些 URL,并且两个依赖项永远不能提供同一个模块。目前没有中央索引,也没有版本锁定,编译器绝不会自行获取或运行另一个项目的构建。

参考中的包为什么编译器有一种“ai”输出格式?

供智能体和其他工具使用。--diagnostic-format=ai 会为每条诊断打印一行,包含精确的跨度以及任何适用的修复,而 axiom symbols 会为每个声明打印一行,带有一个在重新格式化后仍保留的 id,这样工具无需再次读取文件就能了解它提供了什么。人类可读的报告由同一诊断渲染而来,因此两者不会不一致。

诊断与 AXSYM

从想法到可执行文件

用类型思考。
构建原生程序。

你的第一个程序只需几条命令。试用这门语言,检查编译器,并帮助塑造接下来的发展。

开始使用 探索源代码

来源:Hacker News · axiomlang.software