let-go - Go製の7ms起動Clojure系言語
(github.com/nooga)- let-goはGoで書かれたClojure方言で、バイトコードコンパイラとスタックVMを備え、JVMなしで単一の約10MBバイナリとして動作する
- コールドスタートは約7msで、jank-lang Clojure test suite基準のClojure互換性は**4696 / 4921 assertions通過(95.4%)**とされる
- 作者はCLI、スクリプト、Webサーバーに利用しており、let-go上にdaemonless container runtimeも構築していて、スタンドアロン実行バイナリや自己完結型のWASM Webページへコンパイルできる
- 目標はpersistent data structures、lazy seqs、transducers、protocols、records、multimethods、core.async、BigIntsなどClojureの多くの機能の実装と、Go関数・struct・channelとの双方向interopの提供である
- JVM Clojureのdrop-in replacementではなく、JARはロードせず、ライブラリ依存のある実プロジェクトでは調整が必要となる
- Apple M1 Proベンチマークでは、バイナリサイズ10MB、起動時間6.7ms、アイドル時メモリ13.5MBで、Babashka、Joker、go-joker、gloat、Clojure JVMより小さい実行単位で優位性が示されている
- より大きな数値計算処理ではgo-jokerのWASM JITや、ウォームアップ済みのHotSpot JVMが優位で、let-goは大半のアルゴリズムベンチマークでBabashkaと同程度、upstream Jokerより10倍以上高速という結果になっている
- 標準名前空間には
clojure.core、clojure.string、clojure.set、clojure.edn、clojure.test、clojure.core.async、io、http、json、transit、os、System、syscall、podsなどが含まれる - Babashka podsをロードできるため、SQLite、AWS、Docker、ファイル監視などのpodエコシステムを利用でき、
~/.babashka/pods/をbbと共有する - 既知の制限にはRefs / STM、Agents、hierarchies、reader tagged literals、
deftype、reify、clojure.spec、alter-var-root、subseq/rsubseqの未実装と、int64 overflowの自動検出がないことが含まれる - 動作の違いとして、
goブロックはIOC状態マシンではなく実際のgoroutineであり、regexはJava regexではなくGore2を使い、数値体系はint64+float64+BigIntで構成される - インストールはmacOS/Linux向けのHomebrew、Linux・macOS・Windowsのamd64/arm64向けReleases、またはGo 1.22+で
go install github.com/nooga/let-go@latestにより可能 lgはREPL、式eval、ファイル実行をサポートし、.lgbバイトコードのコンパイル、standalone executableのバンドル、WASM Webアプリ生成まで提供する- WASM出力は、inlined WASMを含む約6MB gzippedの自己完結型
index.htmlとservice workerで構成され、term名前空間使用時はxterm.jsベースのターミナルエミュレーションを提供する - 組み込みnREPLサーバーはCIDER、Calva、Conjureと動作し、Goプログラム内では
pkg/apiでlet-goをスクリプティングレイヤーのように埋め込み、Goの値・関数・struct・channelをVMに渡せる
1件のコメント
Hacker Newsのコメント
いいですね! 最近、Goのセマンティクスに Lisp 構文を載せてみる実験をしていました: https://codeberg.org/veqq/Joe
JVM なしの Clojure 系なら Janet も本当に良くて、しばらく本番環境で使っています: https://janet-lang.org/
Lua VM とライブラリが欲しければ Fennel もあります
この Wasm ブラウザ REPL も試してみるとよいです: https://gloathub.org/repl/
Gloat は Glojure AOT の自動化ツールです
昨年の夏に James Hamlin と一緒に Glojure AOT を可能にし、その後も継続して発展させています。marcingas(nooga) とも、Gloat/Glojure/let-go がうまく連携できるよう作業しています
Plan 9 で動くのが驚きです
Go が 9front で一級言語、つまり標準搭載言語になったら素晴らしいですね
Plan 9 向けのソーシャルネットワークをいじっています: https://youtube.com/watch?v=q6qVnlCjcAI&si=MBCeM0QdA0WsKAe7
全部 rc と awk でできていますが、ところどころ Go や Clojure があったらよかったと思う部分があります
amd64 は 9front でテストしていて、すべて問題なく動いているようです。CLI はあまり Plan 9 らしくはありませんが、いずれはもっとネイティブな移植にしたいと思っています
今は Clojure の Go 方言がいくつかあるので、いちばん知りたいのは、どれが Go 上に完全にホストされていて、JVM Clojure が Java と持つレベルの相互運用性を提供するのかという点です
Go から自分が作ったものを使えて、Clojure からも Go を使えて、混成プロジェクトまで作れるとよいですね。また、相互運用性以外にも、何が同じで何がどう違うのかを細かく整理してあるとうれしいです
一方 let-go は、構造体・関数・チャネルを含むどんな Go の値でも往復できますが、任意の Go ライブラリをラッパーなしでそのまま取り込むことはできません。そうしたライブラリはランタイム時にビルドされている必要があります
細かい指摘ですが、README では コールドスタート 7ms と書いてあるのに、数行下では 6ms になっています。README を読むほど速くなるのかもしれませんね
ずっと探していたタイプの Clojure 移植です
Go のコアライブラリとチャネル抽象化のほうが、よりシンプルで優れた基盤 API だと思っていて、core.async 系の API とも相性がよさそうだからです。大きな単一バイナリが欲しいという願いも満たしてくれます
取り組みに感謝します。C++26 への新しい愛着が少し落ち着いたら、ぜひまた見に来るつもりです
それと、なぜ Glojure が自分のレーダーに入っていなかったのかわかりませんが、これも見た感じ素晴らしいプロジェクトですね
昔ながらの PHP と言ったのは、PHP がもともと Web 中心の DSL に近かったからで、今はそうではありません。Go の力を背後に持つ、PHP に似た書きやすいバックエンド言語があれば面白そうで、Clojure はすばらしい選択肢です
代替として Joker もあります: https://joker-lang.org
本当に素晴らしいのに、完全に過小評価されていると思います
ただ、let-go にはあまり多くを追加しすぎたくはありません。10MB 以内に収まるところが気に入っています
言語名は単なる “lets-go” より、もっと良いものがあってもよさそうです。“clogo” はどうでしょう?
(let [...] (go ...))Go で let ができるようにしてくれる!
Clogo は自分にとっては no-go です。他にいい案があれば検討したいです
https://github.com/chr15m/awesome-clojure-likes に PR を送ってくれたら大歓迎です