Show HN: Sigil – 一门面向 AI 智能体的新编程语言

3作者: inerte4 个月前
我一直在开发一种用于 AI 智能体的新编程语言。我非常希望您能提供关于什么让编程语言对 AI 智能体有用的见解,特别是关于语法、编译器和工具,这些可以帮助 AI 智能体编写代码。 是什么让 Sigil 适合编码智能体? 我尽可能地将约定转化为编译器规则。编译器拥有规范的打印器,并且每个 AST 都有一个被接受的文本表示。对于几乎每个语法特性,我都试图节省 token。 强制执行顺序和命名约定。不再有“我认为这个参数很重要,所以它应该放在第一位。” 大部分内容都是按字母顺序排列的。声明按字母顺序分类和排序;参数、效果和记录字段也是按字母顺序排列的。类型使用 UpperCamelCase。其他所有内容都使用 lowerCamelCase,包括文件名。 没有 null。没有 undefined。 双向类型检查。 没有变量遮蔽。 庞大的标准库(仍在开发中)。 `sigil debug` 支持重放、单步调试、监视和断点。 `sigil inspect` 允许编码智能体直接查询编译器,包括证明表面。 基于求解器的精炼和契约。不同的语言已经选择了不同的数值表面:byte、short、smallint、无符号整数等。Sigil 更进一步:域约束也可以定义类型。`where` 允许命名类型携带谓词,而 `requires` / `ensures` 允许函数在调用边界上传递证明义务。 这是一个来自 roguelite 的人为例子: ``` t InventoryCount=Int where value≥0 λspendArrow(arrows:InventoryCount)=&gt;InventoryCount requires arrows&gt;0 ensures result≥0 =arrows-1 ``` 在底层,它由 Z3 提供支持:https://github.com/z3prover/z3,但表面仍然是普通的 Sigil 语法。没有证明脚本,也没有面向用户的 SMT 语言。 没有导入,只有根引用。在某些语言中,您可以导入代码并发生名称冲突,因此有许多方法可以指定导入。Sigil 通过仅使用根引用来消除所有这些。我认为这减少了智能体的流失,因为当模型看到一行时,它不必去寻找导入语句。 服务依赖项在 `src/topology.lib.sigil` 中声明,环境绑定位于 `config/<env>.lib.sigil` 中。 该语言具有用于测试的特殊语法,并且它们是并行运行的。每个项目 `src/*.lib.sigil` 函数都必须经过测试,如果一个函数可以返回多个情况,则测试应该涵盖所有情况。“World”是 Sigil 对效果的模型。这就是模拟的工作方式:用一个效果替换另一个效果,并在不使用真实的外部系统的情况下进行断言。 编译器工具链是用 Rust 编写的,Sigil 输出到 TypeScript,并具有到 Node.js 的外部函数接口。在这里查看一些小型项目 https://inerte.github.io/sigil/projects/ - 闪卡对学习 Sigil 特性很有用 https://inerte.github.io/sigil/projects/sigil-flashcards/demo/ 警告:我没有为编译器工具链编写任何一行代码。所有代码都是使用 Claude Code 和 Codex 生成的。我以危险地跳过权限的方式运行这两个程序。这篇实际的帖子是我手工制作的每一个字。 还有一个用 Sigil 编写的玩具 roguelite。它正在开发中,但它证明了 Sigil 可以支持非平凡的项目代码。您可以玩 `pnpm sigil:run:roguelike`。 存储库:https://github.com/inerte/sigil 网站:https://inerte.github.io/sigil/ 我希望您能找到更多锁定 LLM / 用户程序的方法。在 Sigil 中,应该只有一种方法可以做任何事情。
查看原文
I&#x27;ve been working on a new programming language for AI agents. I would love your input on what makes programming languages good for AI agents, especially syntax, compiler, and tooling that could help AI agents write code.<p>What makes Sigil good for coding agents?<p>I&#x27;ve turned conventions into compiler rules whenever possible. The compiler owns the canonical printer and every AST has one accepted textual representation. For almost every syntax feature I tried to save tokens.<p>Order and naming conventions are enforced. No more &quot;I think this argument is important so it should come first.&quot; Most things are alphabetical. Declarations are categorized and ordered alphabetically; parameters, effects, and record fields are alphabetical too. Types are UpperCamelCase. Everything else is lowerCamelCase, including file names.<p>No nulls. No undefined. Bidirectional type checking. No shadowing. Fat stdlib (still in progress). `sigil debug` supports replay, stepping, watches, and breakpoints. `sigil inspect` lets coding agents query the compiler directly, including proof surfaces.<p>Solver-backed refinements and contracts. Different languages already choose different numeric surfaces: byte, short, smallint, unsigned integers, etc. Sigil pushes that one step further: domain constraints can also define types. `where` lets a named type carry a predicate, and `requires` &#x2F; `ensures` let functions carry proof obligations across call boundaries.<p>Here is a contrived example from the roguelite:<p><pre><code> t InventoryCount=Int where value≥0 λspendArrow(arrows:InventoryCount)=&gt;InventoryCount requires arrows&gt;0 ensures result≥0 =arrows-1 </code></pre> Under the hood this is backed by Z3: <a href="https:&#x2F;&#x2F;github.com&#x2F;z3prover&#x2F;z3" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;z3prover&#x2F;z3</a> But the surface stays ordinary Sigil syntax. There are no proof scripts and no user-facing SMT language.<p>No imports, rooted references only. In some languages you can import code and have name clashes, so there are many ways to specify imports. Sigil eliminates all of that by only using rooted references. I think this reduces agent churn because when the model sees a line, it does not have to go hunt for an import statement.<p>Service dependencies are declared in `src&#x2F;topology.lib.sigil`, and environment bindings live in `config&#x2F;&lt;env&gt;.lib.sigil`.<p>The language has special syntax for tests and they are run in parallel. Every project `src&#x2F;*.lib.sigil` function must be tested, and if a function can return multiple cases, tests should exercise all of them. &quot;World&quot; is Sigil&#x27;s model for effects. That is how mocks work: swap one effect for another and make assertions without exercising real external systems.<p>The compiler toolchain is written in Rust, and Sigil outputs to TypeScript, with a Foreign Function Interface to Node.js. See some small projects here <a href="https:&#x2F;&#x2F;inerte.github.io&#x2F;sigil&#x2F;projects&#x2F;" rel="nofollow">https:&#x2F;&#x2F;inerte.github.io&#x2F;sigil&#x2F;projects&#x2F;</a> - the Flashcards is useful to learn about Sigil features <a href="https:&#x2F;&#x2F;inerte.github.io&#x2F;sigil&#x2F;projects&#x2F;sigil-flashcards&#x2F;demo&#x2F;" rel="nofollow">https:&#x2F;&#x2F;inerte.github.io&#x2F;sigil&#x2F;projects&#x2F;sigil-flashcards&#x2F;dem...</a><p>Caveat: I did NOT type a single line of code for the compiler toolchain. It was all generated with Claude Code and Codex. I run both with permissions dangerously skipped. This actual post I hand crafted every word.<p>There is also a toy roguelite written in Sigil. It is a work in progress, but it is proof that Sigil can support nontrivial project code. You can play with `pnpm sigil:run:roguelike`.<p>Repository: <a href="https:&#x2F;&#x2F;github.com&#x2F;inerte&#x2F;sigil" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;inerte&#x2F;sigil</a><p>Website: <a href="https:&#x2F;&#x2F;inerte.github.io&#x2F;sigil&#x2F;" rel="nofollow">https:&#x2F;&#x2F;inerte.github.io&#x2F;sigil&#x2F;</a><p>And I would love if you can find ways to lock down LLM &#x2F; user programs even more. In Sigil, there should be only one way to do anything.