Skip to main content

Lune — the Lazy and Native programming language

コンパイラが教えてくれる、遅延評価の関数型入門言語。 エラーも、その解説も、母語で読めます。

Lune is a teaching-first functional language: lazy by default, with diagnostics that speak your native language. If you prefer English, start with documents/TUTORIAL_EN.md — every diagnostic and explanation defaults to English.

▶ Playground(インストール不要) · 診断カタログ · チュートリアル

CI Python License: MIT


プロローグ — 全員、部活に入ること

転校初日に知らされた校則がこれだった。「全生徒、いずれかの部に所属すること」。

運動部は続く気がしない。文化系の一覧を眺めていたら「プログラミング部」とある。パソコンで何か打っていれば終わる、いちばん楽そうなやつだ。僕は入部届を出した。

部室のドアには、こう書かれていた。

部訓: 必要になるまで、やらない。一度やったことは、忘れない。

……楽そうな部、で合ってるよな?

入部初日 — さっそく間違える

プログラミング部にはいってみたら、部員は先輩3人だけ、男子は自分だけだった。はたしてやっていけるのかな?

「じゃあ転校生くん、まず書いてみて」と真知(まち)部長。見よう見まねで打ったら、初日からエラーを出した。

let count = 10
let total = cont + 5
$ ./bin/lune --check --lang ja guide.lune
error[TYP0001]: 未定義の名前: cont
  --> guide.lune:2:13
  |
2 | let total = cont + 5
  |             ^^^^ この名前は定義されていない
   = hint: もしかして `count` ですか?
   = help: 詳しくは `lune explain TYP0001 --lang ja` を実行してください

身構えた僕に、部長は画面を指しながら言った。「読み方を教える。上から順に」

  • TYP0001 — エラーの出席番号(診断コード)。あとで調べるときの索引になる
  • ^^^^ — 問題の場所そのもの。まずここを見る
  • = hint: — 次の一手。正解の候補まで書いてある
  • = help: — もっと深く知りたいときの案内

「うちの部では、エラーは赤点じゃなくて教材。読めるようになったら、もう半分書けるのと同じ」

思っていたのと違う。この部、楽じゃない。でも、理不尽でもなかった。

部員紹介 — 教えてくれる先輩たち

  • 真知(まち)部長 — match の抜けを絶対に見逃さない。「Blue のケースがありません」と反例つきで指摘してくる(TYP0007)。書きすぎれば「そのケースには到達しません」(TYP0009)。null も T? の型として扱わせ、?. / ?? / フロー narrowing まで仕込んでくる。厳しいが、指摘には全部理由がある。
  • 英美(えいみ)先輩 — 解説担当。全30の診断コードに「意味・発生する最小例・直し方」の詳解を用意している(lune explain CODE、REPL では :explain)。日本語でも英語でも説明できる(--lang ja)。全文は診断カタログに貼り出されている。
  • 直美(なおみ)先輩 — 赤ペンと清書の担当。typo は did-you-mean の候補で機械的に直してくれるし(lune fix)、提出前には正準スタイルに整えてくれる(lune fmt)。整形で意味が変わっていないことを再パースで検証してから返す、と聞いてこの部の本気度を理解した。

教わる流れは決まっている: 間違える → 読む → explain → fix → 確認。チュートリアル第17章には「指定した診断をわざと出せたら正解」という逆転演習まであって、僕は初日にエラーの出し方から教わった。

部訓の意味 — 「必要になるまで、やらない」(遅延評価)

Lune の値は、必要になるまで計算されない。

let danger = crash()
let answer = 42

answer を評価しても danger は使われないから、crash() は実行されない。「サボりじゃないの。必要なものを、必要なときに、一度だけ。そして一度やったことは忘れない(メモ化)」と部長は言う。

信じられないなら目で見ればいい、と教わったのが REPL の :trace だ。

lune> :trace on
trace on
lune> let y = x + 1
ok                       # 宣言では何も評価されない
lune> y * 10
force y * 10
  force x + 1            # y が必要になって初めて評価される
    memo 1 + 1 => 2      # x はメモ化済み。再計算されない
  => 3
=> 30
30 : Int

この校風なら、無限リストとも普通に付き合える。どこまで計算が進んだかは :thunks が見せてくれる。

lune> let nat = naturalsFrom(1)
ok
lune> head(nat)
Some(1) : Option[Int]
lune> :thunks nat
nat : evaluated = Cons(1, <thunk>)   # 先頭だけ計算済み。続きは手つかず

放課後 — 部室はブラウザの中にもある

https://koide55.github.io/lune-lang/playground/

家に帰ってからも練習できるように、部室はブラウザの中にもある。処理系(Pure Python)が Pyodide 上でそのまま動くので、インストールは不要。実行・型チェック・整形・自動修正・explain・遅延評価のトレース・日本語/英語の切り替え、全部できる。

REPL もそのまま入っている。 出力ペインを「REPL」タブに切り替えると、lune --repl と同じセッションがブラウザの中で立ち上がる — 束縛は残り、:type も :thunks も :trace も効き、複数行の def も書ける。エディタで書いたプログラムを読み込んで、REPL から突くこともできる。

「新規」で白紙から始められるし、手元の .lune ファイルは「開く」(Ctrl/Cmd+O、エディタへのドラッグ&ドロップでも可)で読み込める。書いたコードは「保存」(Ctrl/Cmd+S)で持ち帰れて、そのまま ./bin/lune に食わせられる。

import で分けたプログラムもそのまま動く。 エディタの上のファイルタブで main.lune の隣にモジュールを足せる(math でも util.text でも)。手元でファイルを並べたときとまったく同じ解決規則で、実行も型チェックもプログラム全体が対象になる。

資料棚 — ドキュメント

入部届 — はじめかた

必要なのは Python 3.10+ だけ。依存パッケージはありません。

git clone https://github.com/koide55/lune-lang.git
cd lune-lang

./bin/lune                                 # REPL(:help でコマンド一覧)
./bin/lune --check --lang ja file.lune     # 型チェック(日本語診断)
./bin/lune --eval answer file.lune         # ファイルの束縛を評価
./bin/lune --eval answer --trace file.lune # 遅延評価をトレース
./bin/lune explain TYP0007 --lang ja       # 診断コードの詳解
./bin/lune fmt --write file.lune           # 整形
./bin/lune fix --write file.lune           # typo の自動修正
./bin/lune --version                       # 版番号(バグ報告に添えてください)

書き味の見本は samples/ にあります(ADT・match・レコード・パイプライン |>・nullable・無限ストリームなど)。

pip で入れる

pip で入れると lune コマンドがどこからでも使えます(./bin/lune と同じもの)。

pip install git+https://github.com/koide55/lune-lang.git

lune --check file.lune
LUNE_LANG=ja lune --check file.lune        # 既定を日本語診断にする

クローン済みなら pip install -e . で編集可能インストールにもできます。配布名は lune-lang(PyPI の lune は別のパッケージが使用中)で、PyPI への公開はまだです (手順は documents/RELEASING.md に用意してあります)。

顧問の先生より — 開発者向け

処理系は lune/ 以下の Pure Python(外部依存なし)。lexer → layout → parser → typechecker → evaluator の各層と、diagnostics / explanations / messages(英日メッセージカタログ)/ formatter / fixer / REPL で構成されています。

PYTHONPATH=. python3 -m unittest discover -s tests   # 処理系のテスト
bash books/tools/check_examples.sh                   # 教科書のコード例を実 CLI で検証

テストは「発行されうる全診断コードに詳解があること」「詳解とメッセージに日本語訳があること」「生成物(診断カタログ)が陳腐化していないこと」まで強制します。間違いを教材にする部なので、自分自身にもそこそこ厳しめです。

CI(.github/workflows/ci.yml)は push と PR のたびに、Python 3.10〜3.14 でこの2つを回し、さらに wheel を組んで lune コマンドが単体で動くところまで確かめます。教科書も同じ CI で HTML と PDF に組み上げます(公開しているものと同じ手順です)。

ライセンス

MIT License。Copyright (c) 2026 Hiroshi Koide。


気づけば、放課後の部室にいちばん長く残っているのは僕になっていた。

Lazy は評価戦略のこと。Native はネイティブコードのこと……ではなく native language(母語) のことだと、英美先輩は最初に教えてくれた。それでは、よい部活動を。

Metadata

Release files for lune-lang 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lune-lang 0.1.0
File Size Uploaded
lune_lang-0.1.0.tar.gz 233.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for lune-lang 0.1.0
File Interpreter ABI Platform
lune_lang-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 316.1 kB

Release files / lune_lang-0.1.0.tar.gz

Download URL lune_lang-0.1.0.tar.gz
Size 233.8 kB
Tags Source
SHA-256 checksum
How to use checksums
530dfc4f4b00530f7edad7b609d7294870bf363b58a09d252bde740cb6a594f5
BLAKE2b-256 checksum
How to use checksums
bb6f70fb566cac2d33eb0ee65f64e1da9def984bc6faeaeab8236793701ed852
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.

Transparency log

Release files / lune_lang-0.1.0-py3-none-any.whl

Download URL lune_lang-0.1.0-py3-none-any.whl
Size 82.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9510fc0100ad75eab7055be05e0592fb43190c1d57cb49d79639ed142b9588e6
BLAKE2b-256 checksum
How to use checksums
88f2ea4ebf689da43b2eafad4918e79dbdb4368b0afb2b0ffc6de7864c8148eb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page