見出し画像

実験ノート:Claude Code on the webで、静的型付き関数型プログラミング言語をvibe coding(2)

前の記事では、静的型付き関数型プログラミング言語TreePの言語処理系と、トランスディユーサーをvibe codingした。最後に macro tree transducerを作ってもらった。


Macro Tree Transducer

Macro Tree Trasduderとは、

In principle, macro tree transducers consist of rules, each of them meaning to transform a node of the input tree depending on the node's label. Subsequent functions are called for the children of the transformed node. This means, a macro tree transducer can be considered as a recursive first-order functional program generating trees, where the choice of functions is triggered by top-down pattern matching an input tree. During a computation, macro tree transducers may accumulate intermediate results in additional parameters, and thus have access to context information. Compared to the top-down tree transducer, the ability of carrying context information to further processing steps makes the macro tree transducer the more expressive model.

自分の20年弱前の社会人ドクターのサブテーマ論文、「MDAフレームワークのEDA分野への適用」によると、

Tree Transducerは 、 入 力 木 の ノ ー ドの パ タ ー ン に 対 し て 、 出 力 木 を 生 成 す る 関 数 を 呼 ぶ ル ール の 集 合 で 構 成 さ れ る 。 特 にMacroTreeTransducer(以 下MTTと 略 す)と 呼 ば れ るク ラ ス は 、 入 力 パ タ ー ン に 引 数 を と る こ と が で き る こ と が 特 徴 で 、 木 を 生 成 す る 再 帰 的な1階 関 数 プ ロ グ ラ ム と み な す こ と が で き る 。

サブテーマ論文より

Transduderの実行例(Family Tree)に対応してもらう。

例えば、以下の木構造があるとする、lastNameを先頭に、father、mother、doughterとm-listというノードを起点に木構造が深くなっていく。

入力木

こちらが、MTTの例、

MTTの例

ソ ー ス ノ ー ドがmlistで あ る と き に は 二 分 木 で 展 開 さ れ 子 ノ ー ドがmlistで あ る 場 合は 再 帰 的 に ル ー ル が 呼 ば れ る 。 ま たIastNameはFamilyノ ー ドのrank=1の 子 ノ ー ドに格 納 さ れ て い る の で こ れ を 引 数(y)と し て 他 の ル ー ル を 呼 び 、 最 後 に リ ー フ ノ ー ドで 、lastNameを タ ー ゲ ッ ト枝 に 展 開 し て い る 。

このMTTの出力が以下の木である、男女別に、姓名が枝となった木構造になっている。

出力木の例

どうも、複数状態をもつMTTが必要だったようで、これが実装された

状態は、q0,q,qidの3つがあり、ルールは以下のように展開される。

実行

mtt_transducer.tsから、

Example1:Copy Transducer (No Parameters)

最初は木のコピー

copyルール(一部)

そして入力木が、

入力木

このような出力を得る、当然入力と同じ。

Output tree (should be identical):
{
  "kind": "a",
  "children": [
    {
      "kind": "b",
      "children": [
        {
          "kind": "e"
        },
        {
          "kind": "e"
        }
      ]
    },
    {
      "kind": "e"
    }
  ]
}

Trees are equal: true

同じである。

Example2: Flatten Leaves with Accumulator Parameter

ルールは以下の通り、

入力木が

これをflat化すると、step-by stepではこのように変換され、

Step-by-step execution:
q(a(b(e(), e()), e()), nil)
  → q(b(e(), e()), q(e(), nil))
  → q(b(e(), e()), cons(e(), nil))
  → q(e(), q(e(), cons(e(), nil)))
  → q(e(), cons(e(), cons(e(), nil)))
  → cons(e(), cons(e(), cons(e(), nil)))

出力木は、右よせのリストになる。

Output (right-associated cons list):
{
  "kind": "cons",
  "children": [
    {
      "kind": "e"
    },
    {
      "kind": "cons",
      "children": [
        {
          "kind": "e"
        },
        {
          "kind": "cons",
          "children": [
            {
              "kind": "e"
            },
            {
              "kind": "nil"
            }
          ]
        }
      ]
    }
  ]
}

Example 3: Depth Calculator with Accumulator

そして、ついにパラータ付きのMTT、深さdがパラメータ

入力に対して、

出力は、各ノードに深さが付与されている(depth_x)。

Output (annotated with depths):
{
  "kind": "a",
  "name": "depth_0",
  "children": [
    {
      "kind": "b",
      "name": "depth_1",
      "children": [
        {
          "kind": "e",
          "name": "depth_2"
        },
        {
          "kind": "e",
          "name": "depth_2"
        }
      ]
    },
    {
      "kind": "e",
      "name": "depth_1"
    }
  ]
}

Example 4: Path Accumulator - Build path from root

今度は、ノードに対して、そこまでのパス情報を付与、pathが引数として引き回される。

入力に対し、

出力は、nameにどちらの枝を通ったか履歴が付与される。

Output (annotated with paths):
{
  "kind": "a",
  "name": "root",
  "children": [
    {
      "kind": "b",
      "name": "L",
      "children": [
        {
          "kind": "e",
          "name": "LL"
        },
        {
          "kind": "e",
          "name": "LR"
        }
      ]
    },
    {
      "kind": "e",
      "name": "R"
    }
  ]
}

Example 5: Using MTT with TreeP EAST

これは、TreePのプログラムの木EASTを変換できるという例。
入力h、x+yの関数定義である。

出力は、depthを追加したものが出る。

Output (transformed with depth annotations):
{
  "kind": "function",
  "name": "add",
  "attrs": [
    {
      "key": "nesting_depth",
      "value": "0"
    }
  ],
  "children": [
    {
      "kind": "param",
      "name": "x",
      "attrs": [
        {
          "key": "depth",
          "value": "1"
        }
      ]
    },
    {
      "kind": "param",
      "name": "y",
      "attrs": [
        {
          "key": "depth",
          "value": "1"
        }
      ]
    },
    {
      "kind": "block",
      "attrs": [
        {
          "key": "depth",
          "value": "1"
        }
      ],
      "children": [
        {
          "kind": "return",
          "attrs": [
            {
              "key": "depth",
              "value": "1"
            }
          ],
          "children": [
            {
              "kind": "call",
              "name": "+",
              "attrs": [
                {
                  "key": "depth",
                  "value": "1"
                }
              ],
              "children": [
                {
                  "kind": "var",
                  "name": "x"
                },
                {
                  "kind": "var",
                  "name": "y"
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

Example 6: Family Tree Transformation with Multiple States

そして最後が、Famly Treeの例である。

ルールは、

入力は、

入力木(一部)

わかりやい木構造記述で表現すると、

Input (Family Tree):
Family(
  lastName(March),
  m-list(
    father(Jim),
    m-list(
      mother(Cindy),
      m-list(
        daughter(Brenda),
        e
      )
    )
  )
)

出力は、

Output (Gender-tagged member list with inherited lastName):
{
  "kind": "o",
  "children": [
    {
      "kind": "Male",
      "children": [
        {
          "kind": "identifier",
          "name": "March"
        },
        {
          "kind": "identifier",
          "name": "Jim"
        }
      ]
    },
    {
      "kind": "o",
      "children": [
        {
          "kind": "Female",
          "children": [
            {
              "kind": "identifier",
              "name": "March"
            },
            {
              "kind": "identifier",
              "name": "Cindy"
            }
          ]
        },
        {
          "kind": "o",
          "children": [
            {
              "kind": "Female",
              "children": [
                {
                  "kind": "identifier",
                  "name": "March"
                },
                {
                  "kind": "identifier",
                  "name": "Brenda"
                }
              ]
            },
            {
              "kind": "e"
            }
          ]
        }
      ]
    }
  ]
}

こちらもわかりやすい構造にすると、

Expected structure:
o(
  Male(March, Jim),
  o(
    Female(March, Cindy),
    o(
      Female(March, Brenda),
      e
    )
  )
)

このように、Macro Tree Transducerが実装された。

MTTの応用例

構文器の属性計算

コード生成とXML/HTM変換

感想

TreePの言語処理系をつくったが、ついでにTree Transducerも作った、Macro Tree Transducerに拡張してもらったおかげで、高い変換性能をもつようになり、プログラム変換なんかも可能になった。例題としてTreeP言語のASTの変換例も示してくれた。

木を変換するのはTransducerでこれはルールで記述でき、そして、それは木オートマトンと関連する。ルールからTransducerができてうれしい。

追記:Macro Tree Transducerに糖衣構文(syntax sugar)を追加してもらった

寝起きに、ハッと思い付き、スマホから指示。。

MTTに対する、syntax sugarを設計して、木の構造と、ルールと両方

目が覚めると完成していた。

木構造のsyntax Sugar

そして、MTTのルールは

文法定義はこちら、

むう、寝てる間に作ってくれるって、素晴らしい。

複数のTransducerの合成?

MTT_SYNTAX_SUGAR.mdにこんなことが描いてある。

Transducerの合成

まあ、木変換をパイプラインでつなげるという話だな。。これが実装されているのか?? つづく、、

成果物をここに供養する、


いいなと思ったら応援しよう!