260 likes | 371 Views
二分木操作言語 AATT. メタプログラミングの会 2010 年 12 月 4 日 郵便はみがき. 自己紹介. 郵便はみがき y-hamigaki ( はてな ) yhamigaki (Twitter) ブログ「かそくそうち」 http://d.hatena.ne.jp/y-hamigaki/ フリーソフト 「 Dante98 for Windows 」 ライブラリ「 Hamigaki C++ Libraries 」. 木. ループや孤島がなくノード間の辺が1本. 根. 辺. ノード. 葉. 二分木. 子 の 数が高々2個. 二分探索木.
E N D
二分木操作言語AATT メタプログラミングの会 2010年12月4日 郵便はみがき
自己紹介 郵便はみがき • y-hamigaki(はてな)yhamigaki(Twitter) • ブログ「かそくそうち」 http://d.hatena.ne.jp/y-hamigaki/ • フリーソフト「Dante98 for Windows」 • ライブラリ「Hamigaki C++ Libraries」
木 • ループや孤島がなくノード間の辺が1本 根 辺 ノード 葉
二分木 • 子の数が高々2個
二分探索木 • 小さい値を左の部分木に大きい値を右に 2 1 4 3 5
平衡二分探索木 • 木の偏りを自動的に補正 5 2 4 1 3 4 2 3 5 1
赤黒木 • 根と空ノードは黒 • 赤ノードの子は黒ノード • 根から葉までの黒ノードの数が同じ 2 1 4 0 3 5
赤黒木への挿入 • 赤ノードとして追加 • 赤黒木の制約を満たさない場合は変形 1 2 右回転 2 0 3 1 3 0
パターンマッチなら簡単? • Togetter「kinabaさんが Cryoliteを洗脳してパターンマッチ厨に仕立て上げるリスト」 AAがないと読めません! http://www.cs.kent.ac.uk/people/staff/smk/redblack/Untyped.hs balance :: RB a -> a -> RB a -> RB a balance (T R a x b) y (T R c z d) = T R (T B a x b) y (T B c z d) balance (T R (T R a x b) y c) z d = T R (T B a x b) y (T B c z d) balance (T R a x (T R b y c)) z d = T R (T B a x b) y (T B c z d) balance a x (T R b y (T R c z d)) = T R (T B a x b) y (T B c z d) balance a x (T R (T R b y c) z d) = T R (T B a x b) y (T B c z d) balance a x b = T B a x b
ASCII Art Tree Transform(AATT) • 英小文字→赤ノード、英小文字→黒ノード • 数字→赤ノードか黒ノード • 「^」が探索位置、「*」がルート
AATTのパターンマッチ • 上から順にパターンマッチを行う • 変形後の木に「^」があれば再帰
AATTのパース1 • 空行でパターンを分離
AATTのパース2 • 「->」で入力と出力を分離
AATTのパース3 • 「^」からノードを探索して配列に記録 この順にノードをチェックする
AATTの変形 • 表を見比べて違うリンクとカラーを書き換える
AATT出力例 inline tree_node* balance(tree_node* root, tree_node* node){ tree_node* pN = node; if ((pN != 0) && (pN->color == RED)){ tree_node* pP = pN->parent; if ((pP != 0) && (pP->left == pN) && (pP->color == RED)){ tree_node* pG = pP->parent; if ((pG != 0) && (pG->left == pP) && (pG->color == BLACK)){ tree_node* pU = pG->right; if ((pU != 0) && (pU->color == RED)){ pG->color = RED; pP->color = BLACK; pU->color = BLACK; return balance(root, pG);
D言語への移植 • WYSIWYG文字列でDソースコードに埋め込み • テンプレート実引数に設定 • D言語のソースコードを出力する関数を作成 • mixin文でコンパイル時に評価(CTFE) • dmd 2.050 で確認
D版AATTの問題点1 • mixinコード片中で再帰呼び出しが出来ない { TreeNode!(T)* pN = node; // ... } { TreeNode!(T)* pN = node; if (…) { if (TreeNode!(T)* pP = pN.parent) { node = pP; // ここで自分自身を呼びたい
goto • 末尾再帰なのでgoto文で解決 loop: { TreeNode!(T)* pN = node; // ... } { TreeNode!(T)* pN = node; if (…) { if (TreeNode!(T)* pP = pN.parent) { node = pP; goto loop;
goto文の制約 • 同名の変数定義があるとgotoできない loop: { TreeNode!(T)* pN = node; // ... } { TreeNode!(T)* pN = node; if (…) { if (TreeNode!(T)* pP = pN.parent) { node = pP; goto loop;
変数名に序数を付ける • コード生成関数にシーケンスを渡して別名に loop: { TreeNode!(T)* pN0 = node; // ... } { TreeNode!(T)* pN1 = node; if (…) { if (TreeNode!(T)* pP = pN1.parent) { node = pP; goto loop;
D版AATTの問題点2 • CTFEで再帰呼び出しが出来ない char parseTree( ref AA_TreeNode[] tree, AsciiArtRectaa, AA_TreeNode.Types type, char from, size_t y, size_t x) { // ... node.parent = parseTree( tree, aa, AA_TreeNode.Types.RIGHT_PARENT, c, pos.y, pos.x );
再帰だけど再帰じゃない • 再帰の深度毎に別の関数にしてみる char parseTree(int depth)( ref AA_TreeNode[] tree, AsciiArtRectaa, AA_TreeNode.Types type, char from, size_t y, size_t x) { // ... node.parent = parseTree!(depth+1)( tree, aa, AA_TreeNode.Types.RIGHT_PARENT, c, pos.y, pos.x );
番兵 • ノードは英字26文字+数字10文字のみ • 文法上再帰の深度は35が最大 • 36段目は空ノードしかありえない char parseTree(int depth: 36)( ref AA_TreeNode[] tree, AsciiArtRectaa, AA_TreeNode.Types type, char from, size_t y, size_t x) { return AA_TreeNode.NIL; }
使用例 TreeNode!(T)* balance3a(T)(TreeNode!(T)* root, TreeNode!(T)* node) { return aatt.transform!(T,r" G g / ∖ /^∖ p u -> P U / / n n ^ ")(root, node); }
まとめ • AAで書いたツリー操作がそのままコードに • C++とD(D2)に対応 • Dへのトランスレータさえ書けばCTFEできる • Dは不思議言語 • 次のバージョンでは動かないかも