
2026/06/02 18:34
なぜジェネットなのか?(2023)
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Janet は、お楽しみ用のサイドプロジェクトのために作成されたコンパクトで高性能な命令型言語であり、現在は独立した教育資源へと成長しており、それらに捧げられた無料の本全体が存在します。その最小限のコアは正確に 8 つの命令(do、def、var、set、if、while、break、fn)のみから構成されており、標準ライブラリも 1 ページに収まるため、午後のうちにランタイムの意味論——第一級関数、識別子の単一ネームスペース、およびレキシカルなブロックスコープ——を学ぶことができます。Janet はプログラムをtiny なネイティブ実行ファイルへコンパイルし、その中にガベージコレクターやバイトコードコンパイラーを含む完全なランタイムを静的にリンクさせます(例:「hello world」バイナリが 784K)。これにより依存関係のない共有および新しいコードのランタイム評価が可能になります。
従来の Lisp のフォームとは異なり、Janet は CAR/CDR プライミティブを使用せず、代わりにリストには角括弧、テーブルには花かっこを多用します。さらに、可変なリテラルには
@ プレフィックス、エスケープなしの文字列にはバッククォート、rest パラメータには & を使用します。標準ライブラリに組み込まれた集合型は、単一空間の可変(参照意味論)と不変(値意味論)をユニークにバランスさせており、正規表現の制約なしでマルチラインテキスト、HTML、JSON、バイナリ形式などを処理するパージングエクスプレッショングラマー (PEGs) による高度なテキスト処理をサポートしています。サードパーティ製の sh ライブラリはパイプやリダイレクトへのネイティブサポートを含むシェルスクリプティング DSL を提供しており、Janet を Bash の代替位置づけとしています。その小さな C ライブラリにより、静的サイトやカスタムプログラマブル DSL への埋め込みが容易になります。また、Janet のマクロシステムでは、非引用されたリテラル関数により参照透過性を保ちながらコードを書くコードを記述することができ、トップレベルの状態をディスクへシリアライズすることでコンパイル時からランタイム時の値の渡しが可能にされ、共有参照、可変状態、ジェネレーター、クロージャが保持されます。本文
なぜ今、Janet という言語を学ぶべきなのか
私は過去に Lisp 系言語の経験がなくても良いと考えていましたが、娯楽目的のサイドプロジェクトにおいてJanet(ジェネット)を採用することでその思いが変わりました。以下の理由から、皆様にも Janet を一度試していただきたいです。
1. シンプルさと学習の容易さ
- 命令型かつ関数型: 1 等関数を持ち、識別子は単一のネームスペース、スコーピングはブロックスコーピングを採用しています。
- 最小限のコア: 言語の中核は極めて小さく、以下の 8 つの命令で構成されています。
,do
,def
,var
,set
,if
,while
,breakfn- 注: マクロにより高レベルな制御フローが提供可能です。
- 短い学習曲線: 1 日午後 1 時間で十分習得可能。理由は以下です。
- JavaScript の文法ベースでありつつ、値型を持ち、例外処理などの欠点を排除しています(※原文の「ワットスを排除」は文脈より「例外を排除する意図」と解釈して整理)。
- ライブラリが軽量で、標準ライブラリ全体が1 ページに収まります。
2. 配布と展開の容易さ
- 単一実行ファイル: コンパイルすれば NATIVE のバイナリとして動作します。
- Janet ランタイムが静的にリンクされているため、受入先には事前インストール不要です。
- 「Janet で書かれたものだ」と明言せずともそのまま共有可能です。
- 高度なコンパイル戦略:
- ソースコードをバイトコードへコンパイル。
- バイトコードを C コンパイラで扱いやすい
ファイルへ書き出す。.c - その結果、C ランタイムと埋め込み済み機能を含む1MB 未満のバイナリが生成されます(例: macOS arm64 で約 784KB)。
- 適用シーン: 特に小さなコマンドラインツールの開発に最適です。
3. 優れたテキスト解析能力
- PEG パースング: 正規表現の代わりに、PEG (Parsing Expression Grammar) を採用しています。
- シンプルでありながら強力かつ予測可能。
- 行指向ではないため、マルチラインテキストや HTML/JSON/バイナリファイルなど多様な形式を解析できます。
- 構造化されたパーサー: 「パーサー」として設計されており、組み合わせ容易で学習負担が低いです。
4. シェルスクリプティング用 DSL
というライブラリにより、シェルスクリプティング向けに最適化された DSL を提供します。sh- パイプやリダイレクトなどをネイティブに表現可能(例:
)。($ find . -name *.janet | say) - この高品質な DSL により、Perl や Bash の代替として多くの用途で活躍します。
5. 埋め込み言語としての活用
- Lua のように C ライブラリを通じて他の言語から容易に使用できます。
- 実装が簡単: Janet ランタイムは小さな C ライブラリであり、リンクするだけで完了します。
- 通常の C 関数を呼び出して Janet 値を操作可能。
- ウェブサイトへの埋め込みや、静的サイトの作成にも利用可能です。
6. 不変と可変コレクションの両立
- 両方の型をサポート: 不変(Immutable)と可変(Mutable)のコレクションが存在します。
- 不変: 値セマンティクスを持つ(メモリアドレスが違う場合でも同値)。例:
は[1 2]
と同等。(take 2 [1 2 3]) - 可変: 参照セマンティクスを持つ。別々のハッシュテーブルは別個のオブジェクトとして扱われます。
- 不変: 値セマンティクスを持つ(メモリアドレスが違う場合でも同値)。例:
- 標準ライブラリに不変な合成値を組み込んでいる言語は稀であり、この点は特筆に値します。
7. マクロ機能
- 学習不要でも使える: マクロを習得しなくても十分動作しますが、書くのが楽しいです。
- 思考プロセスの向上:
- コードを書きつつコードを書いているため、「コンパイル時」と「実行時」を同時に考えられます。
- 衛生的なマクロとリテラル関数:
- 独立したネームスペースを持たない代わりに、リテラル関数のアンクォートにより参照的透明なマクロ記述が可能です。
8. コンパイル時とランタイムの境界突破
- 値のシリアライズ化: コンパイル時にディスク上に状態を保存し、後から読み込むことが可能です。
- シリアライズは自動的に発生します(トップレベルで指示が実行され、状態スナップショットが書き出される)。
- フルな状態再開: 共有参照や可変値も保持され、クロージャの閉じ込めも正しく動作します。
- ジェネレータの状態維持や、ゲーム開発でのアセット埋め込み・スプライン計算などに活用できます。
9. シンタックスの手触り(使いやすさ)
- シンプルで一貫性がある:
- リストは
、テーブルは[]
で囲みます。{} - 可変リテラルは
で統一(例:@
,@"string"
)。{:table} - 匿名関数は
またはアップカール記法(fn [x] ...)
を使用します。|... - スパイト展開やスプレッド展開をサポートし、
を使用可能です。; - リテラル文字列はバッククォートで囲み、エスケープ処理を最小限に抑えられます(例:
の考慮不要)。\n - 可変な引数は
で表現します(例:&
)。(defn foo [x & rest] ...)
- リストは
- リーダマクロなし: シンタックスは固定されており、学習すれば全てのプログラムが読めます。
10. 古の慣習からの離脱(現代への適応)
- Lisp などの古い慣習に固執せず、直感的な命名と機能を採用しています。
→carfirst
→progndo
→lambdafn
→setqdef
- 独自な設計:
は空リストではなく独自の型です。nil- 1 等としての Boolean を持っています(EQ/EQL/EQUAL など不要な区別なし)。
- リストと連結リストを同一視しません。
結論: Janet は、分布の容易さ、パース能力の優位性、モダンな設計思想により、様々な開発タスクにおいて強力なツールとなります。まずは Hello World をコンパイルし、その可能性を体感してみてください。