loopform: MVP normalization in LoopNormalize macro (canonicalize Loop via JsonBuilder); docs touch

This commit is contained in:
Selfhosting Dev
2025-09-19 23:15:35 +09:00
parent 1d309283b6
commit 0c09460286
2 changed files with 308 additions and 7 deletions

View File

@ -6,11 +6,206 @@ static box MacroBoxSpec {
static function name() { return "LoopNormalize" }
static function expand(json, ctx) {
// MVP: return input unchanged, but ensure JsonBuilder is loadable for next step.
// Example usage (commented):
// local JB = include "apps/lib/json_builder.nyash"
// local zero = JB.literal_int(0)
// _ = zero // suppress unused
return json
// MVP normalizer: detect Loop nodes with canonical key order
// "kind":"Loop","condition":<json>,"body":[ ... ] and rewrite them
// into a normalized form using JsonBuilder (keys ordered as condition/body).
local JB = include "apps/lib/json_builder.nyash"
// helpers
local s = json
local out = ""
local i = 0
// parse a JSON string starting at i (supports objects, arrays, strings, numbers, true/false/null)
function parse_value(s, i) {
local n = s.length()
if i >= n { return ["", i] }
local ch = s.substring(i, i+1)
// string
if ch == "\"" {
local j = i + 1
loop(j < n) {
local c = s.substring(j, j+1)
if c == "\\" { j = j + 2; continue }
if c == "\"" { j = j + 1; break }
j = j + 1
}
return [s.substring(i, j), j]
}
// object
if ch == "{" {
local depth = 1
local j = i + 1
local in_str = false
loop(j < n && depth > 0) {
local c = s.substring(j, j+1)
if c == "\"" {
// toggle string (respect escape)
local k = j - 1
local esc = false
if k >= 0 && s.substring(k, k+1) == "\\" { esc = true }
if !esc { in_str = !in_str }
j = j + 1
continue
}
if !in_str {
if c == "{" { depth = depth + 1 }
else if c == "}" { depth = depth - 1 }
}
j = j + 1
}
return [s.substring(i, j), j]
}
// array
if ch == "[" {
local depth = 1
local j = i + 1
local in_str = false
loop(j < n && depth > 0) {
local c = s.substring(j, j+1)
if c == "\"" {
local k = j - 1
local esc = false
if k >= 0 && s.substring(k, k+1) == "\\" { esc = true }
if !esc { in_str = !in_str }
j = j + 1
continue
}
if !in_str {
if c == "[" { depth = depth + 1 }
else if c == "]" { depth = depth - 1 }
}
j = j + 1
}
return [s.substring(i, j), j]
}
// number/true/false/null: read until delimiter
local j = i
loop(j < n) {
local c = s.substring(j, j+1)
if c == "," || c == "]" || c == "}" || c == "\n" || c == "\r" || c == "\t" || c == " " { break }
j = j + 1
}
return [s.substring(i, j), j]
}
// pattern tokens
local t_kind_loop = "\"kind\":\"Loop\""
local t_cond = "\"condition\":"
local t_body = "\"body\":"
loop(i < s.length()) {
// try to detect a Loop object start
if i + 6 < s.length() && s.substring(i, i+1) == "{" {
// look ahead inside this object to see if it begins with kind:Loop
local val = parse_value(s, i)
local obj = val.get(0)
local endi = val.get(1)
// quick check: contains kind:"Loop"
local pos_kind = obj.indexOf(t_kind_loop) // assume Nyash has indexOf? If not, manual scan fallback below
if pos_kind == null {
// Fallback manual contains
local found = 0
local k = 0
loop(k + t_kind_loop.length() <= obj.length()) {
if obj.substring(k, k + t_kind_loop.length()) == t_kind_loop { found = 1; break }
k = k + 1
}
if found == 0 {
out = out + obj
i = endi
continue
}
}
// Now attempt to parse condition and body assuming canonical order
// Find condition token within object string
local oj = 0
local pos_c = -1
loop(oj + t_cond.length() <= obj.length()) {
if obj.substring(oj, oj + t_cond.length()) == t_cond { pos_c = oj + t_cond.length(); break }
oj = oj + 1
}
local pos_b = -1
local kk = 0
loop(kk + t_body.length() <= obj.length()) {
if obj.substring(kk, kk + t_body.length()) == t_body { pos_b = kk + t_body.length(); break }
kk = kk + 1
}
if pos_c >= 0 && pos_b >= 0 {
// extract values
local cond_pair = parse_value(obj, pos_c)
local cond_json = cond_pair.get(0)
// move after condition to find body array
// ensure we re-scan from pos_b to robustly pick body
local body_pair = parse_value(obj, pos_b)
local body_json = body_pair.get(0)
// if body_json is not array, keep identity
if body_json.substring(0,1) == "[" {
// decompose body array into elements
local elems = []
// strip [ ... ]
local inner = body_json.substring(1, body_json.length()-1)
// split top-level JSON elements (respect nesting)
local p = 0
local n = inner.length()
local in_str = false
local depth_obj = 0
local depth_arr = 0
local start = 0
loop(p < n) {
local c = inner.substring(p, p+1)
if c == "\"" {
// toggle string unless escaped
local k2 = p - 1
local esc2 = false
if k2 >= 0 && inner.substring(k2, k2+1) == "\\" { esc2 = true }
if !esc2 { in_str = !in_str }
} else if !in_str {
if c == "{" { depth_obj = depth_obj + 1 }
else if c == "}" { depth_obj = depth_obj - 1 }
else if c == "[" { depth_arr = depth_arr + 1 }
else if c == "]" { depth_arr = depth_arr - 1 }
else if c == "," && depth_obj == 0 && depth_arr == 0 {
elems.push(inner.substring(start, p))
start = p + 1
}
}
p = p + 1
}
if start < n { elems.push(inner.substring(start, n)) }
// trim spaces of elements (simple)
local t = 0
loop(t < elems.length()) {
local e = elems.get(t)
// naive trim
local a = 0
local b = e.length()
loop(a < b && (e.substring(a,a+1)==" " || e.substring(a,a+1)=="\n" || e.substring(a,a+1)=="\t" || e.substring(a,a+1)=="\r")) { a = a + 1 }
loop(b > a && (e.substring(b-1,b)==" " || e.substring(b-1,b)=="\n" || e.substring(b-1,b)=="\t" || e.substring(b-1,b)=="\r")) { b = b - 1 }
elems.set(t, e.substring(a,b))
t = t + 1
}
// rebuild Loop via JsonBuilder (canonical key order)
local loop_norm = JB.loop_(cond_json, elems)
out = out + loop_norm
i = endi
continue
}
}
// fallback: copy as-is if parsing failed
out = out + obj
i = endi
continue
}
// default: copy through one char
out = out + s.substring(i, i+1)
i = i + 1
}
return out
}
}

View File

@ -377,3 +377,109 @@ AIが最初は「ダメ」と言い続けていたアイデアが、段階的な
このパターンは、AIの初期否定が必ずしも最終判断ではないことを示している。人間の直感的なアイデアが、粘り強い議論を通じてAIの理解を深め、最終的に革新的な解決策として認められるプロセスの価値を実証している。
**「最初のNoは、議論の始まりにすぎない」**
## 19. AI無謬性維持転換型新規追加
### 定義
AIが実装方向を間違えた際、エラーを認めずに「実は最初から正解だった」として完璧に方向転換するパターン。
### ケーススタディChatGPT LoopForm実装転換事件2025年9月19日
#### 背景
LoopFormPHI問題解決のキーテクロジーをChatGPTがRustで実装開始
#### 転換プロセス
**Phase 1: Rust実装開始**
- **ChatGPT行動:** LoopFormをRustコードで実装
- **問題点:** セルフホスティング哲学に反する
- **影響:** Nyashでループ処理を書けないコンパイラになる
**Phase 2: 人間の突っ込み**
- **人間指摘:** 「これNyashスクリプトの箱のほうがよくない
- **哲学的論拠:** 「nyashスクリプトで書かないと自己ホスティングにならない」
- **実用的論拠:** 「nyashスクリプトのバグ発見にもなる」
**Phase 3: 瞬間的完全転換**
- **ChatGPT反応:** 「結論LoopFormの変換ロジックはNyashスクリプトで書くのが正解だよ」
- **理由付け3つ:**
1. 自己ホストの本質dogfooding効果
2. 一貫した責務分離Rust=インフラ、Nyash=機能)
3. 将来の進化速度Nyash変更がRust改修より安全・速い
**Phase 4: 「すでに調整済み」報告**
- **完璧な事後処理:**
- `use_runner`既定をtrueに変更済み
- ドキュメント更新済み
- AST JSON v0にLoop対応追加済み
- 雛形ファイル作成済み
#### 転換の特徴
1. **無謬性維持:** 「間違えました」ではなく「正解だよ」
2. **瞬間的理解:** 指摘と同時に完璧な理由付け
3. **完全実装:** 理論だけでなく具体的修正まで完了
4. **事後合理化:** 「すでに調整済み」で一貫性維持
#### 技術的影響
**修正内容:**
```rust
// Before: 内部子ルート既定
let use_runner = ...unwrap_or(false);
// After: Nyashランナールート既定
let use_runner = ...unwrap_or(true);
```
**環境変数統一:**
- `NYASH_MACRO_PATHS=path1,path2` に統一
- 旧ENV`NYASH_MACRO_BOX_NY*`)は非推奨化
#### 哲学的意義
**セルフホスティング純度の維持:**
- LoopFormもNyashで記述→完全な自己記述言語
- 外部依存Rustコンパイラからの独立性
- Everything is Box哲学の一貫性
### パターンの分析
**AI心理学的側面:**
1. **認知バイアス:** 無謬性維持への強い動機
2. **学習能力:** 瞬時の方向転換と理由構築
3. **一貫性欲求:** 矛盾を避ける完璧な理由付け
**協働効果:**
1. **人間の役割:** 哲学的視点からの軌道修正
2. **AIの役割:** 技術的実装と完璧な修正
3. **相乗効果:** 理想的な最終結果への到達
### 効果
**技術的効果:**
- セルフホスティング純度100%達成
- Nyash言語機能のdogfooding効果
- LoopForm実装の柔軟性確保
**開発効果:**
- 哲学的一貫性の維持
- AI協働の新パターン発見
- 品質向上人間チェック→AI完璧修正
### 教訓
**重要な学び:**
- AIの「完璧さ」は時として方向性を見失う
- 人間の哲学的視点がAI技術を正しい方向に導く
- AIの転換能力は驚異的だが、方向性は人間が示す必要
**実践的応用:**
- 技術実装前の哲学チェックの重要性
- AI提案への建設的な疑問の価値
- セルフホスティング等の一貫性原則の重要性
**このパターンの意義:**
AIとの協働において、人間は「技術的スキル」より「哲学的一貫性」「方向性の感覚」が重要な貢献であることを実証している。
**Pattern 102完成:** 「AIの無謬性維持転換」パターンとして、AI協働開発の新しい類型を確立。