Seven Trees 解答

ref: http://d.hatena.ne.jp/ku-ma-me/20081023/p1
ref: http://d.hatena.ne.jp/m-hiyama/20081031/1225416719

ポイントは檜山さんが書かれているように、T = 1 + T^2 を使って T から T^7 への式変形を構成するところです。

その式変形は以下。各行は T^0 〜 T^8 までの係数を並べて書いています (T なら 0 1 0 0 0 0 0 0 0 、1 + T^2 なら 1 0 1 0 0 0 0 0 0 、という感じ) 。

0 1 0 0 0 0 0 0 0
 / \
1 0 1 0 0 0 0 0 0
   / \
1 1 0 1 0 0 0 0 0
     / \
1 1 1 0 1 0 0 0 0
       / \
1 1 1 1 0 1 0 0 0
         / \
1 1 1 1 1 0 1 0 0
           / \
1 1 1 1 1 1 0 1 0
             / \
1 1 1 1 1 1 1 0 1
           / \
1 1 1 1 1 2 0 1 1
         / \
1 1 1 1 2 1 1 1 1
     \ /
1 1 0 2 1 1 1 1 1
   \ /
1 0 1 1 1 1 1 1 1
 \ /
0 1 0 1 1 1 1 1 1
   \ /
0 0 1 0 1 1 1 1 1
     \ /
0 0 0 1 0 1 1 1 1
       \ /
0 0 0 0 1 0 1 1 1
         \ /
0 0 0 0 0 1 0 1 1
           \ /
0 0 0 0 0 0 1 0 1
             \ /
0 0 0 0 0 0 0 1 0

ちょうど 18 ステップでした。美しいですね。


面白かったのはここまでで、後は苦行。馬鹿正直に実装にするには、各行ごとに対応する型をバリアントとして定義していきます。

-- 0 1 0 0 0 0 0 0 0 の型
data Step0 = Step0_1 Tree

-- 1 0 1 0 0 0 0 0 0 の型
data Step1 = Step1_0
           | Step1_2 Tree Tree

-- 1 1 0 1 0 0 0 0 0 の型
data Step2 = Step2_0
           | Step2_1 Tree
           | Step2_3 Tree Tree Tree

-- 1 1 1 0 1 0 0 0 0 の型
data Step3 = Step3_0
           | Step3_1 Tree
           | Step3_2 Tree Tree
           | Step3_4 Tree Tree Tree Tree

...

-- 1 1 1 1 2 1 1 1 1 の型
data Step9 = Step9_0
           | Step9_1   Tree
           | Step9_2   Tree Tree
           | Step9_3   Tree Tree Tree
           | Step9_4_a Tree Tree Tree Tree
           | Step9_4_b Tree Tree Tree Tree
           | Step9_5   Tree Tree Tree Tree Tree
           | Step9_6   Tree Tree Tree Tree Tree Tree
           | Step9_7   Tree Tree Tree Tree Tree Tree Tree
           | Step9_8   Tree Tree Tree Tree Tree Tree Tree Tree

...

-- 0 0 0 0 0 0 0 1 0 の型
data Step18 = Step18_7 Tree Tree Tree Tree Tree Tree Tree

係数が 2 のところはバリアントも 2 つ書かないといけないところに注意。
そして Step と Step の双方向の変換を書きます。

step0_to_step1 :: Step0 -> Step1
step0_to_step1 (Step0_1 Leaf)         = Step1_0
step0_to_step1 (Step0_1 (Node tl tr)) = Step1_2 tl tr

step1_to_step2 :: Step1 -> Step2
step1_to_step2  Step1_0                  = Step2_0
step1_to_step2 (Step1_2 t0 Leaf)         = Step2_1 t0
step1_to_step2 (Step1_2 t0 (Node tl tr)) = Step2_3 t0 tl tr

step2_to_step3 :: Step2 -> Step3
step2_to_step3  Step2_0                     = Step3_0
step2_to_step3 (Step2_1 t0)                 = Step3_1 t0
step2_to_step3 (Step2_3 t0 t1 Leaf)         = Step3_2 t0 t1
step2_to_step3 (Step2_3 t0 t1 (Node tl tr)) = Step3_4 t0 t1 tl tr

...

step1_to_step0 :: Step1 -> Step0
step1_to_step0  Step1_0        = Step0_1 Leaf
step1_to_step0 (Step1_2 tl tr) = Step0_1 (Node tl tr)

step2_to_step1 :: Step2 -> Step1
step2_to_step1  Step2_0           = Step1_0
step2_to_step1  Step2_1 t0        = Step1_2 t0 Leaf
step2_to_step1 (Step2_3 t0 tl tr) = Step1_2 t0 (Node tl tr)

step3_to_step2 :: Step3 -> Step2
step3_to_step2  Step3_0              = Step2_0
step3_to_step2  Step3_1 t0           = Step2_1 t0
step3_to_step2  Step3_2 t0 t1        = Step2_3 t0 t1 Leaf
step3_to_step2 (Step3_4 t0 t1 tl tr) = Step2_3 t0 t1 (Node tl tr)

...

あとはこれらをつなげて f と g を書きます。

f :: Tree7 -> Tree
f (t0, t1, t2, t3, t4, t5, t6) =
  (\ (Step0_1 t) -> t) $
  step1_to_step0 $
  step2_to_step1 $
  ...
  step17_to_step16 $
  step18_to_step17 $
  Step18_7 t0 t1 t2 t3 t4 t5 t6 t7

g :: Tree -> Tree7
g t =
  (\ (Step18_7 t0 t1 t2 t3 t4 t5 t6) -> (t0, t1, t2, t3, t4, t5, t6)) $
  step17_to_step18 $
  step16_to_step17 $
  ...
  step1_to_step2 $
  step0_to_step1 $
  Step0_1 t

これで終わり。ふう。


ぼくが実際に書いたプログラムは、以下のようにステップを短くして、

0 1 0 0 0 0 0 0 0
 / \
1 0 1 0 0 0 0 0 0
   / \
1 1 0 1 0 0 0 0 0
     / \
1 1 1 0 1 0 0 0 0
       / \
1 1 1 1 0 1 0 0 0
         / \
1 1 1 1 1 0 1 0 0
     \ /   / \
1 1 0 2 0 1 0 1 0
   \ /       / \
1 0 1 1 0 1 1 0 1
 \ /       / \
0 1 0 1 0 2 0 1 1
   \ /   / \
0 0 1 0 1 1 1 1 1
     \ /
0 0 0 1 0 1 1 1 1
       \ /
0 0 0 0 1 0 1 1 1
         \ /
0 0 0 0 0 1 0 1 1
           \ /
0 0 0 0 0 0 1 0 1
             \ /
0 0 0 0 0 0 0 1 0

バリアントを使いまわしたものです。

module Main where
import Control.Monad
import Test.QuickCheck

data Tree = Leaf | Node Tree Tree deriving (Eq, Show)
type Tree7 = (Tree, Tree, Tree, Tree, Tree, Tree, Tree)

instance Arbitrary Tree where
    arbitrary = oneof [ return Leaf, liftM2 Node arbitrary arbitrary ]
instance
  (Arbitrary a, Arbitrary b, Arbitrary c, Arbitrary d,
   Arbitrary e, Arbitrary f, Arbitrary g) =>
   Arbitrary (a, b, c, d, e, f, g) where
    arbitrary =
      return (,,,,,,)
        `ap` arbitrary `ap` arbitrary `ap` arbitrary `ap` arbitrary
        `ap` arbitrary `ap` arbitrary `ap` arbitrary

data Value = T0
           | T1  Tree
           | T2  Tree Tree
           | T3a Tree Tree Tree
           | T3b Tree Tree Tree
           | T4  Tree Tree Tree Tree
           | T5a Tree Tree Tree Tree Tree
           | T5b Tree Tree Tree Tree Tree
           | T6  Tree Tree Tree Tree Tree Tree
           | T7  Tree Tree Tree Tree Tree Tree Tree
           | T8  Tree Tree Tree Tree Tree Tree Tree Tree
           deriving (Eq, Show)

f :: Tree7 -> Tree
f (it0, it1, it2, it3, it4, it5, it6) = ot
 where v1 = T7 it0 it1 it2 it3 it4 it5 it6
       v2 = case v1 of
              T7  t0 t1 t2 t3 t4 t5 Leaf         -> T6  t0 t1 t2 t3 t4 t5
              T7  t0 t1 t2 t3 t4 t5 (Node tl tr) -> T8  t0 t1 t2 t3 t4 t5 tl tr
              v                                  -> v
       v3 = case v2 of
              T6  t0 t1 t2 t3 t4    Leaf         -> T5a t0 t1 t2 t3 t4
              T6  t0 t1 t2 t3 t4    (Node tl tr) -> T7  t0 t1 t2 t3 t4    tl tr
              v                                  -> v
       v4 = case v3 of
              T5a t0 t1 t2 t3       Leaf         -> T4  t0 t1 t2 t3
              T5a t0 t1 t2 t3       (Node tl tr) -> T6  t0 t1 t2 t3       tl tr
              v                                  -> v
       v5 = case v4 of
              T4  t0 t1 t2          Leaf         -> T3a t0 t1 t2
              T4  t0 t1 t2          (Node tl tr) -> T5a t0 t1 t2          tl tr
              v                                  -> v
       v6 = case v5 of
              T3a t0 t1             Leaf         -> T2  t0 t1
              T3a t0 t1             (Node tl tr) -> T4  t0 t1             tl tr
              v                                  -> v
       v7 = case v6 of
              T2  t0                Leaf         -> T1  t0
              T2  t0                (Node tl tr) -> T3a t0                tl tr
              T4  t0 t1 t2 t3                    -> T5b t0 t1 t2 t3       Leaf
              T6  t0 t1 t2 t3       tl tr        -> T5b t0 t1 t2 t3       (Node tl tr)
              v                                  -> v
       v8 = case v7 of
              T1                    Leaf         -> T0
              T1                    (Node tl tr) -> T2                    tl tr
              T5b t0 t1 t2 t3 t4                 -> T6  t0 t1 t2 t3 t4    Leaf
              T7  t0 t1 t2 t3 t4    tl tr        -> T6  t0 t1 t2 t3 t4    (Node tl tr)
              v                                  -> v
       v9 = case v8 of
              T2  t0                Leaf         -> T1  t0
              T2  t0                (Node tl tr) -> T3b t0                tl tr
              T6  t0 t1 t2 t3 t4 t5              -> T7  t0 t1 t2 t3 t4 t5 Leaf
              T8  t0 t1 t2 t3 t4 t5 tl tr        -> T7  t0 t1 t2 t3 t4 t5 (Node tl tr)
              v                                  -> v
       vA = case v9 of
              T3b t0 t1             Leaf         -> T2  t0 t1
              T3b t0 t1             (Node tl tr) -> T4  t0 t1             tl tr
              T5a t0 t1 t2 t3 t4                 -> T6  t0 t1 t2 t3 t4    Leaf
              T7  t0 t1 t2 t3 t4    tl tr        -> T6  t0 t1 t2 t3 t4    (Node tl tr)
              v                                  -> v
       vB = case vA of
              T4  t0 t1 t2 t3                    -> T5a t0 t1 t2 t3       Leaf
              T6  t0 t1 t2 t3       tl tr        -> T5a t0 t1 t2 t3       (Node tl tr)
              v                                  -> v
       vC = case vB of
              T3a t0 t1 t2                       -> T4  t0 t1 t2          Leaf
              T5a t0 t1 t2          tl tr        -> T4  t0 t1 t2          (Node tl tr)
              v                                  -> v
       vD = case vC of
              T2  t0 t1                          -> T3a t0 t1             Leaf
              T4  t0 t1             tl tr        -> T3a t0 t1             (Node tl tr)
              v                                  -> v
       vE = case vD of
              T1  t0                             -> T2  t0                Leaf
              T3a t0                tl tr        -> T2  t0                (Node tl tr)
              v                                  -> v
       vF = case vE of
              T0                                 -> T1                    Leaf
              T2                    tl tr        -> T1                    (Node tl tr)
              v                                  -> v
       (T1 ot) = vF

g :: Tree -> Tree7
g it = (ot0, ot1, ot2, ot3, ot4, ot5, ot6)
 where v1 = T1 it
       v2 = case v1 of
              T1                    Leaf         -> T0
              T1                    (Node tl tr) -> T2                    tl tr
              v                                  -> v
       v3 = case v2 of
              T2  t0                Leaf         -> T1  t0
              T2  t0                (Node tl tr) -> T3a t0                tl tr
              v                                  -> v
       v4 = case v3 of
              T3a t0 t1             Leaf         -> T2  t0 t1
              T3a t0 t1             (Node tl tr) -> T4  t0 t1             tl tr
              v                                  -> v
       v5 = case v4 of
              T4  t0 t1 t2          Leaf         -> T3a t0 t1 t2
              T4  t0 t1 t2          (Node tl tr) -> T5a t0 t1 t2          tl tr
              v                                  -> v
       v6 = case v5 of
              T5a t0 t1 t2 t3       Leaf         -> T4  t0 t1 t2 t3
              T5a t0 t1 t2 t3       (Node tl tr) -> T6  t0 t1 t2 t3       tl tr
              v                                  -> v
       v7 = case v6 of
              T2  t0 t1                          -> T3b t0 t1             Leaf
              T4  t0 t1             tl tr        -> T3b t0 t1             (Node tl tr)
              T6  t0 t1 t2 t3 t4    Leaf         -> T5a t0 t1 t2 t3 t4
              T6  t0 t1 t2 t3 t4    (Node tl tr) -> T7  t0 t1 t2 t3 t4    tl tr
              v                                  -> v
       v8 = case v7 of
              T1  t0                             -> T2  t0                Leaf
              T3b t0                tl tr        -> T2  t0                (Node tl tr)
              T7  t0 t1 t2 t3 t4 t5 Leaf         -> T6  t0 t1 t2 t3 t4 t5
              T7  t0 t1 t2 t3 t4 t5 (Node tl tr) -> T8  t0 t1 t2 t3 t4 t5 tl tr
              v                                  -> v
       v9 = case v8 of
              T0                                 -> T1                    Leaf
              T2                    tl tr        -> T1                    (Node tl tr)
              T6  t0 t1 t2 t3 t4    Leaf         -> T5b t0 t1 t2 t3 t4
              T6  t0 t1 t2 t3 t4    (Node tl tr) -> T7  t0 t1 t2 t3 t4    tl tr
              v                                  -> v
       vA = case v9 of
              T1  t0                             -> T2  t0                Leaf
              T3a t0                tl tr        -> T2  t0                (Node tl tr)
              T5b t0 t1 t2 t3       Leaf         -> T4  t0 t1 t2 t3
              T5b t0 t1 t2 t3       (Node tl tr) -> T6  t0 t1 t2 t3       tl tr
              v                                  -> v
       vB = case vA of
              T2  t0 t1                          -> T3a t0 t1             Leaf
              T4  t0 t1             tl tr        -> T3a t0 t1             (Node tl tr)
              v                                  -> v
       vC = case vB of
              T3a t0 t1 t2                       -> T4  t0 t1 t2          Leaf
              T5a t0 t1 t2          tl tr        -> T4  t0 t1 t2          (Node tl tr)
              v                                  -> v
       vD = case vC of
              T4  t0 t1 t2 t3                    -> T5a t0 t1 t2 t3       Leaf
              T6  t0 t1 t2 t3       tl tr        -> T5a t0 t1 t2 t3       (Node tl tr)
              v                                  -> v
       vE = case vD of
              T5a t0 t1 t2 t3 t4                 -> T6  t0 t1 t2 t3 t4    Leaf
              T7  t0 t1 t2 t3 t4    tl tr        -> T6  t0 t1 t2 t3 t4    (Node tl tr)
              v                                  -> v
       vF = case vE of
              T6  t0 t1 t2 t3 t4 t5              -> T7  t0 t1 t2 t3 t4 t5 Leaf
              T8  t0 t1 t2 t3 t4 t5 tl tr        -> T7  t0 t1 t2 t3 t4 t5 (Node tl tr)
              v                                  -> v
       (T7 ot0 ot1 ot2 ot3 ot4 ot5 ot6) = vF

main :: IO ()
main = do
    quickCheck $ \x -> x == f (g x)
    quickCheck $ \x -> x == g (f x)

ながー。5 分岐とかは全然考えてないです。