View
229
Download
9
Embed Size (px)
Citation preview
二分木操作言語 AATT
メタプログラミングの会2010 年 12 月 4 日
郵便はみがき
自己紹介郵便はみがき• y-hamigaki( はてな ) yhamigaki(Twitter)• ブログ「かそくそうち」
http://d.hatena.ne.jp/y-hamigaki/• フリーソフト「 Dante98 for Windows」• ライブラリ「 Hamigaki C++ Libraries」
2
木
• ループや孤島がなくノード間の辺が1本根
辺
葉
ノード
二分木• 子の数が高々2個
二分探索木• 小さい値を左の部分木に大きい値を右に
2
1 4
3 5
平衡二分探索木• 木の偏りを自動的に補正
2
1 4
3 52
1
4
3
5
赤黒木• 根と空ノードは黒• 赤ノードの子は黒ノード• 根から葉までの黒ノードの数が同じ
2
1 4
3 50
赤黒木への挿入• 赤ノードとして追加• 赤黒木の制約を満たさない場合は変形
1
3
20
2
0
31右回転
パターンマッチなら簡単?• Togetter 「 kinaba さんが Cryolite を洗脳
してパターンマッチ厨に仕立て上げるリスト」
AA がないと読めません!
balance :: RB a -> a -> RB a -> RB abalance (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
http://www.cs.kent.ac.uk/people/staff/smk/redblack/Untyped.hs
ASCII Art Tree Transform(AATT)
• 英小文字→赤ノード、英小文字→黒ノード
• 数字→赤ノードか黒ノード• 「 ^ 」が探索位置、「 * 」がルート*
G P
/ ∖ / ∖
p U — > n g
/ ∖ / ∖
n 3 3 U
^
AATT のパターンマッチ• 上から順にパターンマッチを行う• 変形後の木に「 ^ 」があれば再帰
G P
/ ∖ / ∖
p U — > n g
/ ∖ / ∖
n 3 3 U
^
G P
/ ∖ / ∖
U p p — > g n
/ ∖ / ∖
3 3 n U 3
^
AATT のパース 1
• 空行でパターンを分離G P
/ ∖ / ∖
p U — > n g
/ ∖ / ∖
n 3 3 U
^
G P
/ ∖ / ∖
U p p — > g n
/ ∖ / ∖
3 3 n U 3
^
AATT のパース 2
• 「 -> 」で入力と出力を分離
G P
/ ∖ / ∖
p U — > n g
/ ∖ / ∖
n 3 3 U
^
AATT のパース 3
• 「 ^ 」からノードを探索して配列に記録
この順にノードをチェックする
G
/ ∖
p U
/ ∖
n 3
^
名前 親 左 右 種別
N P nil nil 起点
P G N 3 右親
3 P nil nil 右子
G nil P U 右親
U G nil nil 右子
AATT の変形• 表を見比べて違うリンクとカラーを書き
換える名前 親 左 右 種別
N P nil nil 起点
P G N 3 右親
3 P nil nil 右子
G nil P U 右親
U G nil nil 右子
名前 親 左 右 種別
N P nil nil 左子
P nil N G 起点
3 G nil nil 左子
G P 3 U 右子
U G nil nil 右子
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, AsciiArtRect aa, 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, AsciiArtRect aa, 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, AsciiArtRect aa, 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 は不思議言語• 次のバージョンでは動かないかも