概要
- let-go はGoで書かれたClojure方言の言語
- JVM不要・単一10MBバイナリ・7ms高速起動
- Clojureコードの約95%互換(jank-langテスト基準)
- CLI・スクリプト・Webサーバ・WASM・Go組み込み用途に最適
- JVM完全互換やJAR読込は非対応、用途特化型言語
let-go概要
- let-go は、 Go で実装された Clojure方言 および バイトコードコンパイラ+スタックVM
- 単一10MBバイナリ で配布、 JVM不要、 約7msのコールドスタート
- Clojure の約 95%互換 (jank-langテストスイート基準)
- 2021年に「 Goを書いているフリをしながらClojureを書く」というジョークから開発開始
- CLIツール、スクリプト、Webサーバ、daemonlessコンテナランタイム などで実用
- スタンドアロンバイナリ や 自己完結型WASMページ へのコンパイル対応
- Plan 9 でも動作確認済み
- JVM Clojureの完全な代替 ではなく、 JAR読込非対応 ・一部ライブラリ利用時は調整が必要
主要な特徴・目標
- Clojureの主要機能 (永続データ構造、遅延シーケンス、トランスデューサ、プロトコル、レコード、マルチメソッド、core.async、BigIntなど)を実装
- Goとの双方向インタープリタ (関数・構造体・チャンネルの相互利用)
- AOTコンパイル によるバイトコード生成・スタンドアロンバイナリ作成
- WASMページへのコンパイル (ターミナルエミュレーション付き)
- nREPLサーバ 搭載(Calva, CIDER, Conjure等に対応)
- Babashka Pod 互換で豊富なPodエコシステムを活用可能
- コンテナランタイムやCLI、Webサーバ、Go組み込みスクリプト層 としての利用
ベンチマーク・比較
- バイナリサイズ :let-go 10MB(最小)、Babashka 68MB、Clojure JVM 304MB
- 起動速度 :let-go 6.7ms(Babashkaの約3倍、JVMの約50倍高速)
- アイドル時メモリ :let-go 13.5MB(最小)
- 短命なデータ処理 (map/filter/persistent map等)で高速
- 数値演算系の大規模ワークロード ではgo-jokerやJVMが優位
- Babashkaと同等性能 のアルゴリズムベンチマーク多数
- Joker(上流)比で10倍以上高速
互換性・サポート状況
- jank-lang/clojure-test-suite で 95.4% のアサーション合格
- clojure.core, clojure.string, clojure.set, clojure.walk, clojure.edn, clojure.pprint, clojure.test, core.async など主要名前空間をカバー
- Babashka Pods のロード対応(SQLite, AWS, Docker等のPod利用可)
- ~/.babashka/pods/ を共用し、bbでPodインストール後let-goから利用
既知の制限事項
- 未実装 :Refs/STM, Agents, 階層(derive等)、chunked sequence、タグ付きリテラル、deftype/reify、Spec、alter-var-root
- 数値のオーバーフロー検出非対応 (int64でサイレントラップ、BigInt演算子は別途用意)
- 一部動作の差異 :concat*はeager、Goチャンネルは常にブロック、数値タワーはint64/float64/BigIntのみ、正規表現はGo(re2)準拠
実例・利用例
- xsofy :同一ソースでブラウザ・ターミナル両対応のローグライク
- lgcr :syscall名前空間を活用したdaemonlessコンテナランタイム
- examples/ :小規模サンプル
- test/ :.lgテストファイル
インストール・利用方法
- Homebrew対応 (macOS/Linux):
brew tap nooga/let-go→brew install let-go - バイナリ配布 :Linux, macOS, Windows(amd64/arm64)向け
- Go 1.22+でソースビルド :
go install github.com/nooga/let-go@latest - 基本コマンド :
lg:REPL起動lg -e '(+ 1 1)':式評価lg myfile.lg:ファイル実行lg -r myfile.lg:ファイル実行後REPLlg -c app.lgb app.lg:バイトコードへコンパイルlg -b myapp app.lg:自己完結バイナリ作成lg -w site app.lg:WASM Webアプリ化
WASM・Webアプリ対応
- 自己完結型index.html (~6MB, WASM内包, gzip圧縮)
- xterm.js連携 でフルターミナルエミュレーション(ANSIカラー、カーソル、キーボード入力)
- COOP/COEPヘッダ 付与用Service Worker同梱(GitHub Pages対応)
nREPLサーバ
- Emacs(CIDER) :
M-x cider-connect-cljで接続 - VS Code(Calva) :プロジェクトREPL起動または直接接続
- Neovim(Conjure) :
.nrepl-port存在時に自動接続 - 対応ops :clone, close, eval, load-file, describe, completions, info, lookup, ls-sessions, interrupt
Goプログラムへの組み込み
- Goからlet-go VMを起動・関数/構造体/チャンネルを渡してスクリプト実行
- Go側の構造体→let-goレコード化、Goチャンネル→let-goチャンネル化
- Go関数→let-goから呼び出し可能
- 詳細例 :
pkg/api/interop_test.goにサンプル多数
テスト・開発
- テスト実行 :
go test ./... -count=1 -timeout 30s - GitHubページ/リポジトリ : https://github.com/nooga/let-go
- 作者の他プロジェクト :paserati(Go製TypeScriptランタイム、20MBバイナリ)
まとめ・補足
- let-go は ピュアGo実装のClojureライク言語、JVM不要・高速起動・小型バイナリ
- nREPL・WASM・Go連携 ・Podエコシステム活用など多機能
- 既存Clojureプロジェクトの完全移植は非推奨、用途特化・新規開発やCLI/スクリプト・組み込み利用に最適
- コミュニティ参加・PR歓迎、気軽に試用・フィードバック推奨