世界を動かす技術を、日本語で。

Nanolang: コーディングLLMを対象とするために設計された小さな実験言語

2026年1月20日原文(github.com)

概要

NanoLangは、 シンプル かつ LLMフレンドリー なプログラミング言語。 Cへの トランスパイル によるネイティブ性能と 明快な構文 を両立。 全関数に 必須テスト を要求し、AIによるコード生成にも最適化。 自己ホスティング や自動依存管理など、現代的な機能を搭載。 主要OSで動作し、学習・貢献も容易な設計。

NanoLang概要

  • NanoLang は、最小限かつ AIに優しい構文 を持つプログラミング言語
  • C言語へのトランスパイル により、ネイティブ並みの高速実行を実現
  • 全関数に必須のシャドウテスト を導入し、品質担保
  • 自己ホスティング (Stage 0 → Stage 1 → Stage 2ブートストラップ)をサポート
  • 明示的な構文前置記法 により、AIや人間にも誤解のないコード生成

インストールとクイックスタート

  • GitHubリポジトリ からクローン: git clone https://github.com/jordanhubbard/nanolang.git
  • ディレクトリ移動:cd nanolang
  • ビルド:make build
    • bin/nanoc:NanoLangコンパイラ(Cコードへトランスパイル)

Hello World例

  • hello.nanoファイル作成:

    fn greet(name: string) -> string {
      return (+ "Hello, " name)
    }
    shadow greet {
      assert (str_equals (greet "World") "Hello, World")
    }
    fn main() -> int {
      (println (greet "World"))
      return 0
    }
    shadow main { assert true }
    
  • ビルド&実行:

    • ./bin/nanoc hello.nano -o hello
    • ./hello

プラットフォームサポート

  • Tier 1(完全サポート)

    • Ubuntu 22.04+(x86_64)
    • Ubuntu 24.04(ARM64:Raspberry Pi, AWS Graviton等)
    • macOS 14+(Apple Silicon)
    • FreeBSD
  • Tier 2(WSL経由でサポート)

    • Windows 10/11(WSL2で動作)

      • PowerShellでwsl --install -d Ubuntu
      • WSL内で通常のインストール手順
    • 理由 :NanoLangの依存(SDL2, ncurses, pkg-config)はUnix/POSIXライブラリ

    • 注意 :現時点でWindowsネイティブバイナリ(.exe)は未対応

  • Tier 3(実験的)

    • macOS Intel(Rosetta 2経由または旧Macでネイティブ)
    • その他Linux(Arch, Fedora, Debian等)
    • OpenBSD(依存手動インストール)

主な特徴

  • 前置記法 :演算子の優先順位なし、常に明確な構文
  • 必須テスト :全関数にシャドウテストブロック必須
  • 静的型付け :コンパイル時型チェック
  • ジェネリック型 :Result<T, E>等によるエラーハンドリング
  • C言語インターフェース :FFIサポート&自動依存管理
  • 標準ライブラリ :Result<T, E>、文字列操作、数学等
  • モジュールシステム :module.jsonによる自動依存管理

ドキュメントと学習パス

  • User Guide(HTML) :段階的チュートリアル+実行可能スニペット
  • Getting Started :15分で学べるチュートリアル
  • Quick Reference :構文チートシート
  • Language Specification :完全リファレンス
  • Examples :全機能を網羅した動作例

言語構文・型システム

  • 変数宣言 :let x: int = 42(デフォルトimmutable)、let mutでmutable
  • 関数定義 :fn add(a: int, b: int) -> int { ... }
  • 必須テスト :shadow add { assert (== (add 2 3) 5) }
  • 制御構文 :if/else, while
  • ループ例 :while (< i 10) { print i set i (+ i 1) }
    • プリミティブ:int, float, bool, string, void
    • 構造体:struct Point { x: int, y: int }
    • 列挙型:enum Status { Pending = 0, Active = 1, Complete = 2 }
    • ジェネリックリスト:let numbers: List<int> = (List_int_new)
    • 第一級関数:let f: fn(int) -> int = double
    • ジェネリックユニオン:union Result<T, E> { Ok { value: T }, Err { error: E } }

標準ライブラリ例

  • Result型によるエラーハンドリング

    union Result<T, E> { Ok { value: T }, Err { error: E } }
    fn divide(a: int, b: int) -> Result<int, string> {
      if (== b 0) { return Result.Err { error: "Division by zero" } }
      return Result.Ok { value: (/ a b) }
    }
    fn main() -> int {
      let result: Result<int, string> = (divide 10 2)
      match result {
        Ok(v) => (println v.value),
        Err(e) => (println e.error)
      }
      return 0
    }
    

代表的なサンプル

  • コア例 :hello.nano, calculator.nano, factorial.nano, fibonacci.nano, primes.nano
  • ゲーム例 :snake_ncurses.nano, game_of_life_ncurses.nano, asteroids_complete.nano, checkers.nano, boids_sdl.nano
  • examples/README.md で全リスト確認可能

モジュールと自動依存管理

  • グラフィックス・ゲーム用
    • ncurses(ターミナルUI)、sdl(2Dグラフィックス)、sdl_mixer(音声)、sdl_ttf(フォント)、glfw(OpenGL)
    • 初回利用時にHomebrewやapt等で自動インストール
    • 詳細:docs/MODULE_SYSTEM.md

ビルド&テスト

  • ビルド :make build(3段階ブートストラップ)
  • 全テスト :make test
  • クイックテスト :make test-quick
  • 全サンプルビルド :make examples
  • 例ブラウザ起動 :make examples-launcher
  • ユーザーガイド検証 :make userguide-check
  • 静的HTML生成 :make userguide-html
  • ローカルサーブ :make -C userguide serve
  • クリーンビルド :make clean
  • インストール :sudo make install(PREFIX指定可)
  • BSD系 :gmake build, gmake test等

LLMへのNanoLang教育

  • LLM向け設計 :曖昧さのない構文+必須テストでAIの学習効率向上
  • MEMORY.md :構文、パターン、デバッグ手法、よくあるエラー等を網羅
  • spec.json :公式な型・標準ライブラリ・構文仕様
  • examples/ :全機能の実用例
  • 推奨学習順
    • MEMORY.mdで実践知識習得
    • spec.jsonで形式仕様確認
    • examplesでイディオム把握

貢献方法

  • 貢献歓迎 :例追加、ドキュメント改善、バグ報告・機能提案、新モジュール・標準関数実装
  • ガイドライン :CONTRIBUTING.md参照

プロジェクトステータス

  • 現状 :自己ホスティング対応の本番運用コンパイラ
  • 実装済み機能
    • 完全な言語実装(字句解析・構文解析・型検査・トランスパイル)
    • Cトランスパイルによる高速化
    • 型推論付き静的型付け
    • 構造体・列挙型・ユニオン・ジェネリクス
    • モジュール自動依存管理
    • 49以上の標準関数
    • 90以上の動作例
    • シャドウテストフレームワーク
    • CライブラリFFI
    • メモリ安全機能
  • 今後の計画 :docs/ROADMAP.md参照

NanoLangの意義

  • AIコード生成 :曖昧さのない構文でAIの誤りを低減
  • テスト重視 :必須テストで品質向上
  • シンプル&高速 :最小限のキーワード・構文、C由来の高性能

設計思想

  • 最小限の構文 (キーワード18個、Cは32個)
  • 唯一明快な方法 で記述
  • テストを言語仕様に組み込み、後付けではない
  • Cトランスパイル で最大互換性

ライセンス・リンク

  • ライセンス :Apache License 2.0(LICENSE参照)
  • ドキュメント :docs/
  • サンプル :examples/
  • イシュー :GitHub Issues
  • 貢献ガイド :CONTRIBUTING.md

Hackerたちの意見

ここでの新しいポイントは、すべての関数にコンパイル時に実行されるテストが必要だってこと。カスタム言語をLLMに教える価値があるのか、LuaやPythonみたいな既存の言語を使ってテスト要件を適用する方がいいんじゃないかって、まだ疑問に思ってる。

PyretっていうCSのための教育用言語は、Racketみたいな感じで、関数を書くことでテストが必要なんだよね。 https://pyret.org/docs/latest/testing.html

それが新しいかどうかはわからないけど、例でないものに関しては信号対ノイズ比がどうなるか疑問だな。実際のソースコードのファイルは、テストによって完全に汚染されるか(テストは実際のコードよりもずっと長いから)、fn process_order { ... }のような影のprocess_order { assert test_process_order }になって、テストコードは別のファイルに書かれ、テストコード内のすべての関数には真を主張する影の関数があって、コンパイラを喜ばせることになると思う。

NVIDIAのジョーダン・ハバードが開発したやつだね(FreeBSDも)。私の理解や経験から言うと、LLMのパフォーマンスは、その言語がトレーニングデータにどれだけよく表現されているかに依存する。だから、トレーニングコードが多くある既存の言語の方が、たとえその言語が複雑で理解しにくそうでも、実際にはLLMがうまくいく可能性があると思う。

新しい言語やフレームワークには、特に新しいアイデアがある場合、悲しいことにそういうことが多いと思う。

これって、あなたのワークフローによるところが大きいよね。優れた型付けや型チェック、良いコンパイラエラーを持つ言語は、表面のオーバーヘッドや構文が複雑な言語よりもループ内でうまく機能する。たとえそれがよく表現されていてもね。これは、例えば、https://github.com/toon-format/toon のようなJSONの代替フォーマットの背後にある考え方だよ。彼らはそのフォーマットでLLMの精度をJSONと比較してテストしていて、(一般的にJSONより少し進んでいる)。さらに、LLMに対して全体の言語を文脈に入れる能力、つまりすべてを説明する単一のドキュメントがあれば、ギャップを埋める可能性が高い。いくつかのナノファイルをざっと見たけど、見た目が好きとは言えないけど、すごくクリアに見えた。おそらくそれが利点になるね。

言語がどれだけよく表現されているかだけじゃないんだよね。あまり知られていないAPIはLLMを混乱させることがある。私はATProtoを使ったFlutterプロジェクトでAntigravityを使ってるけど、GeminiはDartコーディングが得意で、17番目の管理言語を習得するのが楽だった。FlutterのUI要素も得意だし。ただ、ATProtoとそのDart APIに関しては、明らかに苦手だった。失敗の特徴が面白かったよ。予想通り、過剰なリファクタリングは大失敗で、簡単に元に戻せた。でも、FlutterプロジェクトでAndroidのランチャーアイコンを再生成するようなシンプルなことは、完全に盲点だった。ジャングルを走り回る裸の野蛮人みたいにググらなきゃいけなかった。

正直、私の経験はそうじゃない。良いコードベースがあって、良いツールがあれば、そして本当に良いプロンプトがあれば、かなりマイナーなものでも素晴らしい結果が得られたよ。自家製の言語も含めてね。他の人が言ったように、鍵はフィードバックとプロンプティングだと思う。長いコンテキストを持つモデルなら、きっと理解できるはず。

その仮定は成り立たないと思う。例えば、最近になってエージェントがRustのコードを初回で正しく書けるようになったけど、過去にはそれが重要じゃなかったんだ。なぜなら、Rustのコンパイラやリンターがすごく良いフィードバックをくれるから、すぐにミスを修正できるからね。これによって文脈が少し早く埋まるけど、(1) 動的言語で問題をデバッグするほどではないし、(2) より良いエージェントフレームワークが出てきて、動的に文脈を圧縮するために「書き換え」てくれるようになるよ。

既存の言語に対して、こういう新しい言語への「トランスピレーション」レイヤーを作る方法があるのかな?そうすれば、他の言語からのトレーニングを全部活用できるかもしれない。ASTからASTへの何かね。ただ、最初のトレーニングやファインチューニングの段階でしか機能しないのかも。

私の理解/経験では、LLMのパフォーマンスは言語がトレーニングデータにどれだけよく表現されているかに比例する。 これは本当じゃないよ。LLMは文法をすごくよく理解してる。もしあなたの言語に文法があれば、LLMは一発で完璧なコードを生成できる。彼らが知らないのは、その言語の周りのツールなんだ。でも、これも結構簡単に解決できるよ。彼らはCLIツールを探るのが得意だから。

ブラックピルは、こういう理由で、今ある主流のプログラミング言語が、グローバルに関連する最後の(人間が設計した)言語になるってことだ。最終的にはAIが自分たちの言語を作るようになるだろうし、人間はもちろん趣味で言語をデザインし続けるだろう。でも、影響力の面では、プログラミングの世界を席巻するような人間の言語はもう出てこないと思う。残された時間があまりにも少ないからね。

Hacker Newsで議論の続きを見る