Files
hakorune/docs/private/roadmap/language-evolution/desugaring-contract.md

556 lines
14 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🎯 De-sugaring Contractデシュガリング契約
**作成日**: 2025-10-02
**対象**: すべての新機能実装
**関連**: [言語進化ロードマップ v2.0](./README.md)
---
## 📖 概要
**De-sugaring Contractデシュガリング契約** は、Hakoruneの**最も重要な設計原則**です。
> **新構文は既存構文・既存Boxへ有限段で必ず落ちること。IR命令の追加は最後の手段。**
この原則により、**「コアは最小・糖衣は最強」** を実現します。
---
## 🎯 5つの不変ルール赤線
### **1⃣ MIR14は増やさない**
**原則**: すべてデシュガリング/静的パス/標準ライブラリで実現
**現状のMIR14命令セット**:
- 基本演算(5): Const, UnaryOp, BinOp, Compare, TypeOp
- メモリ(2): Load, Store
- 制御(4): Branch, Jump, Return, Phi
- 呼び出し(1): MirCallCallee で Global/Extern/ModuleFunction/Method/Constructor/Closure/Value を表現)
- GC(2): Barrier, Safepoint
- 構造(2): Copy, Nop最適化/検証用・意味論不変)
📖 **詳細**: [MIR Instruction Set](../../../reference/mir/INSTRUCTION_SET.md)
**なぜ凍結するか**:
- VM/LLVM/WASMすべてのバックエンドで恩恵を受ける
- セルフホストの保守性が維持される
- 実装の複雑度が爆発しない
---
### **2⃣ Everything is Box/flow Main.main を維持**
**原則**: すべての値はBox、すべての関数はBox/flowのメソッド
```nyash
// ✅ 正しい設計
box OptionBox<T> {
value: T
is_some: BoolBox
birth(v: T) {
me.value = v
me.is_some = true
}
unwrap(): T {
if not me.is_some {
panic("unwrap on None")
}
return me.value
}
}
// T? → OptionBox<T> へデシュガリング
local x: IntegerBox? = getSomeValue()
// ↓
local x: OptionBox<IntegerBox> = getSomeValue()
```
**Pulse は下限**:
- 最小限の型として利用
- 言語機能には持ち込まない
---
### **3⃣ Effects/Capabilities/Contracts は meta 側**
**原則**: 言語仕様には持ち込まない、metaレイヤーで処理
```nyash
// ❌ 言語機能化(採用しない)
effect IO {
read(path: StringBox): ResultBox<StringBox>
write(path: StringBox, data: StringBox): ResultBox<Unit>
}
fn process() with IO {
// IO効果を要求
}
// ✅ meta側で処理視覚糖衣のみ
with net.out, fs.read {
http.get("https://api.example.com")
file.read("config.txt")
}
// ↓ 実際は何も変えない(ログに印を出すだけ)
```
**効果システムの取り扱い**:
- **静的解析ツール**で検出Linter/型チェッカー)
- **ランタイムは関与しない**
- **視覚的な開発体験向上**のみ
---
### **4⃣ 例外は導入しない**
**原則**: panicはVM/実装バグ用、通常はResultBoxで伝播
```nyash
// ✅ 正しいエラー処理ResultBox + ? 演算子)
box FileBox {
read(path: StringBox): ResultBox<StringBox> {
// エラー時はResultBox::Err返却
}
}
flow Main.main() {
local content = FileBox::read("config.txt")? // ? で伝播
processContent(content)
}
// ❌ 例外(採用しない)
try {
let content = FileBox::read("config.txt")
} catch(FileNotFoundError e) {
// ...
}
```
**panic の用途**:
- VM内部エラー配列境界外アクセス等
- 実装バグunreachable!相当)
- **通常のエラーハンドリングには使わない**
---
### **5⃣ dev→prod の挙動差は policy のみ**
**原則**: warn/audit/enforce で制御
```nyash
// ✅ policy制御
debug_assert(internal.isValid()) // dev: panic, prod: nop
// ❌ 挙動差を言語機能に(採用しない)
if DEBUG_MODE {
checkInvariant()
}
```
**policy種別**:
- **warn**: 警告のみ
- **audit**: ログ記録
- **enforce**: エラーdev/prod共通
---
## 🍬 デシュガリング実例集
### **A. 型システム**
#### **Optional型 `T?`**
```nyash
// 糖衣構文
local x: IntegerBox? = getSomeValue()
// ↓ デシュガリング後
local x: OptionBox<IntegerBox> = getSomeValue()
// OptionBoxは標準ライブラリで実装
box OptionBox<T> {
value: T
is_some: BoolBox
birth(v: T) { me.value = v; me.is_some = true }
birth_none() { me.is_some = false }
unwrap(): T { /* ... */ }
is_some(): BoolBox { return me.is_some }
is_none(): BoolBox { return not me.is_some }
}
```
**MIR命令増加**: なし既存のMirCall, Branch, Return等で実現
#### **Union型 `A|B`**
```nyash
// 糖衣構文
type Result = OkBox | ErrorBox
// ↓ デシュガリング後
type Result = SumBox<OkBox, ErrorBox>
// SumBoxは標準ライブラリで実装
box SumBox<A, B> {
tag: StringBox // "A" or "B"
value_a: A
value_b: B
birth_left(a: A) { me.tag = "A"; me.value_a = a }
birth_right(b: B) { me.tag = "B"; me.value_b = b }
match_sum<R>(on_left: fn(A) -> R, on_right: fn(B) -> R): R {
if me.tag == "A" {
return on_left(me.value_a)
} else {
return on_right(me.value_b)
}
}
}
```
**MIR命令増加**: なし
---
### **B. 並行処理**
#### **`async {}` スコープ**
```nyash
// 糖衣構文
async {
nowait task1 = longTask1()
nowait task2 = longTask2()
// スコープ終了で自動待機
}
// ↓ デシュガリング後
local group = new TaskGroupBox()
group.spawn(fn() { longTask1() })
group.spawn(fn() { longTask2() })
group.await_all() // スコープ終了時自動
// TaskGroupBoxは標準ライブラリで実装
box TaskGroupBox {
tasks: ArrayBox<FutureBox>
spawn(task: fn()) {
local future = nowait task()
me.tasks.push(future)
}
await_all() {
loop(me.tasks.len() > 0) {
local future = me.tasks.pop()
await future
}
}
}
```
**MIR命令増加**: なし既存のnowait/awaitで実現
#### **`select {}` 式**
```nyash
// 糖衣構文
match select {
ch1.receive() => { handle1() }
ch2.receive() => { handle2() }
timeout(1000) => { handleTimeout() }
}
// ↓ デシュガリング後
local sel = new SelectBox()
sel.on(ch1, fn(v) { handle1() })
sel.on(ch2, fn(v) { handle2() })
sel.on_timeout(1000, fn() { handleTimeout() })
sel.run()
// SelectBoxは標準ライブラリで実装
box SelectBox {
channels: ArrayBox<ChannelBox>
handlers: ArrayBox<fn(Any)>
on(ch: ChannelBox, handler: fn(Any)) {
me.channels.push(ch)
me.handlers.push(handler)
}
on_timeout(ms: IntegerBox, handler: fn()) { /* ... */ }
run() {
// poll all channels, invoke first ready handler
}
}
```
**MIR命令増加**: なし
---
### **C. 糖衣構文**
#### **パイプライン演算子 `|>`**
```nyash
// 糖衣構文
value |> f(_) |> g(_, 42) |> h(_)
// ↓ デシュガリング後
h(g(f(value), 42))
// 実用例
[1, 2, 3, 4, 5]
|> map(_, fn(x) { x * 2 })
|> filter(_, fn(x) { x % 3 == 0 })
|> reduce(_, 0, fn(acc, x) { acc + x })
// ↓ デシュガリング後
reduce(filter(map([1,2,3,4,5], fn(x){x*2}), fn(x){x%3==0}), 0, fn(acc,x){acc+x})
```
**MIR命令増加**: なし(ただの関数呼び出し順序変更)
#### **名前付き引数**
```nyash
// 糖衣構文
download(url: u, timeout: 3.s, retry: 5)
// ↓ デシュガリング後(位置引数 + デフォルト補完)
download(u, 3.s, 5)
// 欠けた引数はデフォルト補完
download(url: u)
// ↓
download(u, DEFAULT_TIMEOUT, DEFAULT_RETRY)
```
**MIR命令増加**: なし(静的パスで位置引数に変換)
#### **`with capability` スコープ**
```nyash
// 糖衣構文
with net.out, fs.read {
http.get("https://api.example.com")
file.read("config.txt")
}
// ↓ デシュガリング後(何も変えない)
// metaレイヤーでログに印を出すだけ
http.get("https://api.example.com")
file.read("config.txt")
```
**MIR命令増加**: なし(完全に視覚糖衣)
---
### **D. マクロ**
#### **`@test` マクロ**
```nyash
// 糖衣構文
@test
it("should add numbers") {
local calc = new Calculator()
expect(calc.add(2, 3)).toBe(5)
}
// ↓ デシュガリング後HIRパッチ
TestRunnerBox::register("should add numbers", fn() {
local calc = new Calculator()
expect(calc.add(2, 3)).toBe(5)
})
// TestRunnerBoxは標準ライブラリ
static box TestRunnerBox {
tests: ArrayBox<TestCase>
register(name: StringBox, test: fn()) {
me.tests.push(new TestCase(name, test))
}
run_all() {
loop(me.tests.len() > 0) {
local test = me.tests.pop()
test.run()
}
}
}
```
**MIR命令増加**: なしHIRレベルでパッチ
#### **`@profile` マクロ**
```nyash
// 糖衣構文
@profile
calculate() {
// 処理
}
// ↓ デシュガリング後HIRパッチ
calculate() {
local _prof = ProfileBox::start("calculate")
// 処理
_prof.end()
}
// ProfileBoxは標準ライブラリ
box ProfileBox {
name: StringBox
start_time: TimeBox
static start(name: StringBox): ProfileBox {
local prof = new ProfileBox()
prof.name = name
prof.start_time = TimeBox::now()
return prof
}
end() {
local duration = TimeBox::now() - me.start_time
ConsoleBox::log("Profile: " + me.name + " took " + duration.toString())
}
}
```
**MIR命令増加**: なし
---
## 📊 デシュガリング規則一覧表
| 構文 | デシュガリング後 | 実装方法 | MIR命令増加 | Phase |
|------|----------------|---------|------------|-------|
| `T?` | `OptionBox<T>` | 標準ライブラリ | なし | 20 |
| `A\|B` | `SumBox<A,B>` | 標準ライブラリ | なし | 20 |
| `x \|> f(_)` | `f(x)` | 静的パスAST変換 | なし | 17-18 |
| `f(a:1, b:2)` | `f(1,2)` | 静的パス(引数並び替え) | なし | 18-19 |
| `async { body }` | `TaskGroupBox::scoped(...)` | 標準ライブラリ | なし | 22 |
| `select { ... }` | `SelectBox::new()...run()` | 標準ライブラリ | なし | 23 |
| `@test it(...){...}` | `TestRunnerBox::register(...)` | マクロHIRパッチ | なし | 16.1 |
| `@bench(iter:N) { ... }` | `BenchmarkBox::run(...)` | マクロHIRパッチ | なし | 16.3 |
| `@profile { ... }` | `ProfileBox::start()` + `.end()` | マクロHIRパッチ | なし | 20 |
| `repr(obj)` | `@derive(Debug)` 連携 | マクロHIRパッチ | なし | 18 |
| `x.move()` | 所有権移転メソッド | 標準ライブラリ | なし | 28 |
| `x.share()` | Arc参照増加メソッド | 標準ライブラリ | なし | 28 |
| `x.weak()` | 弱参照取得メソッド | 標準ライブラリ | なし | 28 |
| `with cap { ... }` | (何も変えない) | 視覚糖衣meta | なし | 20-22 |
| `comptime { ... }` | 定数埋め込み | 静的パス(ビルド時評価) | なし | 22-25 |
| `pattern Some(x)` | `OptionBox::Some(x)` | 静的パス(パターン別名) | なし | 23-25 |
**重要**: すべてMIR命令増加なし
---
## 🔍 デシュガリング検証方法
### **1. コンパイラフラグ**
```bash
# デシュガリング前のAST表示
$ hakorune --dump-ast program.hkr
# デシュガリング後のHIR表示
$ hakorune --dump-hir program.hkr
# 最終MIR表示MIR14のみ
$ hakorune --dump-mir program.hkr
```
### **2. スモークテスト**
```bash
# デシュガリング検証スイート
$ tools/smokes/v2/run.sh --profile desugaring
```
### **3. Linter検出**
```bash
# レガシー命令検出
$ HAKO_OPT_DIAG=1 hakorune program.hkr
# レガシー命令禁止Fail-Fast
$ HAKO_OPT_DIAG_FORBID_LEGACY=1 hakorune program.hkr
```
---
## 🚨 契約違反の例(やってはいけない)
### **❌ 悪い例1: MIR命令を追加**
```rust
// ❌ NG: Optional型のために新命令追加
enum MirInstruction {
// ... 既存14命令 ...
SomeCheck(ValueId), // ← 追加してはいけない!
NoneCheck(ValueId), // ← 追加してはいけない!
}
// ✅ OK: OptionBoxで実現
box OptionBox<T> {
is_some(): BoolBox { return me.is_some }
// MirCall で呼び出し(既存命令)
}
```
### **❌ 悪い例2: 効果システムを言語機能に**
```nyash
// ❌ NG: 効果システムを型システムに統合
effect IO {
read(path: StringBox): ResultBox<StringBox>
}
fn process() with IO {
// VM/コンパイラが効果を追跡
}
// ✅ OK: meta側で処理視覚糖衣
with io {
process() // ログに印を出すだけ
}
```
### **❌ 悪い例3: 例外を導入**
```nyash
// ❌ NG: try-catch構文を実装
try {
dangerousOp()
} catch(NetworkError e) {
// ...
}
// ✅ OK: ResultBox + ? 演算子
local result = dangerousOp()? // Err時は早期return
```
---
## 📚 参考資料
- [MIR Instruction Set](../../../reference/mir/INSTRUCTION_SET.md) - MIR14命令セット詳細
- [言語進化ロードマップ v2.0](./README.md) - 実装計画
- [Phase 16 Macro Revolution](../phases/phase-16-macro-revolution/README.md) - マクロシステム詳細
- [Discoverability問題分析](./discoverability-analysis.md) - 発見性問題と解決策
---
## 🎊 まとめ
**De-sugaring Contractデシュガリング契約** により、Hakoruneは
1.**コアは最小** - MIR14命令セットを凍結
2.**糖衣は最強** - すべての新機能をデシュガリング/Box/マクロで実現
3.**保守性最高** - セルフホストの実装容易性維持
4.**一貫性抜群** - Everything is Box哲学貫徹
5.**拡張性無限** - Box/マクロでいくらでも拡張可能
この原則により、**次世代言語の標準** を打ち立てます。
---
**作成者**: Claude Sonnet 4.5 + ChatGPT Pro
**作成日**: 2025-10-02
**関連**: [言語進化ロードマップ v2.0](./README.md)