第13章 プログラムの論証 #7
13.9 練習問題
- 以下の定義が与えられているとする。
map f [] = [] map f (x:xs) = f x : map f xs (f.g) x = f (g x)map f (map g xs) = map (f.g) xsであることを、xsに対する数学的帰納法で証明せよ。
xs = []の場合左辺 = map f (map g []) = map f [] = [] 右辺 = map (f.g) [] = []
xs = nsのときに式が成り立つと仮定して、xs = n:nsの場合左辺 = map f (map g (n:ns)) = map f (g n : map g ns) = f (g n) : map f (map g ns) = (f.g) n : map (f.g) ns 右辺 = map (f.g) (n:ns) = (f.g) n : map (f.g) ns
n = 0の場合左辺 = take 0 xs ++ drop 0 xs = [] ++ xs = xs = 右辺
n > 0, xs = []の場合左辺 = take n [] ++ drop n [] = [] ++ [] = [] = 右辺
n = m, xs = ysで式が成り立つと仮定して、n = m+1, xs = y:ysの場合左辺 = take (m+1) (y:ys) ++ drop (m+1) (y:ys) = (y: take m ys) ++ (drop m ys) = y : (take m ys ++ drop m ys) = y:ys = 右辺
ヒント通り、木の葉と節の個数を数える関数を定義する。
countLeaf :: Tree -> Int countLeaf Leaf _ = 1 countLeaf Node l r = countLeaf l + countLeaf r countNode :: Tree -> Int countNode Leaf _ = 0 countNode Node l r = 1 + countNode l + countNode r
その上で、countLeaf t = countNode t + 1が常に成り立つことをを証明する。
t = Leaf nの場合左辺 = countLeaf Leaf n = 1 右辺 = countNode Leaf n + 1 = 0 + 1 = 1
t = lおよびt = rで式が成り立つと仮定してt = Node l rの場合左辺 = countLeaf Node l r = countLeaf l + countLeaf r = (countNode l + 1) + (countNode r + 1) = 2 + countNode l + countNode r 右辺 = countNode Node l r + 1 = 1 + countNode l + countNode r + 1 = 2 + countNode l + countNode r
compの定義を再掲しておく。
comp :: Expr -> Code comp (Val n) = [Push n] comp (Add x y) = comp x ++ comp y ++ [ADD]
e = Val nの場合comp' (Val n) c = [Push n] ++ c = Push n : c
e = xおよびe = yでcomp' e c = comp e ++ cが成り立つと仮定してe = Add x yの場合comp' (Add x y) c = comp x ++ comp y ++ [ADD] ++ c = comp' x (comp y ++ [ADD] ++ c) = comp' x (comp' y (ADD : c))
まとめると
comp' :: Expr -> Code -> Code comp' (Val n) c = Push n : c comp' (Add x y) c = comp' x (comp' y (ADD : c))
ついに終わった……