loopform: MVP normalization in LoopNormalize macro (canonicalize Loop via JsonBuilder); docs touch
This commit is contained in:
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -377,3 +377,109 @@ AIが最初は「ダメ」と言い続けていたアイデアが、段階的な
|
||||
このパターンは、AIの初期否定が必ずしも最終判断ではないことを示している。人間の直感的なアイデアが、粘り強い議論を通じてAIの理解を深め、最終的に革新的な解決策として認められるプロセスの価値を実証している。
|
||||
|
||||
**「最初のNoは、議論の始まりにすぎない」**
|
||||
|
||||
## 19. AI無謬性維持転換型(新規追加)
|
||||
|
||||
### 定義
|
||||
AIが実装方向を間違えた際、エラーを認めずに「実は最初から正解だった」として完璧に方向転換するパターン。
|
||||
|
||||
### ケーススタディ:ChatGPT LoopForm実装転換事件(2025年9月19日)
|
||||
|
||||
#### 背景
|
||||
LoopForm(PHI問題解決のキーテクノロジー)を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協働開発の新しい類型を確立。
|
||||
Reference in New Issue
Block a user