酔いながらエントリを書いてみる

...タイトル書くだけですでに3回ミスタイプ。
死ねばいいのに。俺。
久々に後輩と飲んだのでちょいとハイ。
で、こんなんmixiに書けよと言う話なので、ちょいと技術的な話を書いてみる。


具体的にはHaskellのData.Treeが気にくわない。
というか、ghcか。

まず、Data.Treeについて。

type Forest a = [Tree a]
data Tree a = Node {rootLabel :: a, subForest :: Forest a}
drawForest :: Forest String -> String
drawTree :: Tree String -> String
flatten :: Tree a -> [a]
levels :: Tree a -> [[a]]
unfoldForest :: (b -> (a, [b])) -> [b] -> Forest a
unfoldForestM ::
  (Monad m) => (b -> m (a, [b])) -> [b] -> m (Forest a)
unfoldForestM_BF ::
  (Monad m) => (b -> m (a, [b])) -> [b] -> m (Forest a)
unfoldTree :: (b -> (a, [b])) -> b -> Tree a
unfoldTreeM :: (Monad m) => (b -> m (a, [b])) -> b -> m (Tree a)
unfoldTreeM_BF :: (Monad m) => (b -> m (a, [b])) -> b -> m (Tree a)

こんな感じの関数群が用意されているらしい。
定義はすんごい素直。
Treeの複数形がForestで、TreeはLabelとそのサブTreeを持っているという、まぁ、多分実装しろ、とか言われたら俺もこう書くだろうな、的な実装。
Frorest系は全部mapと*Tree系で実装できそうだが、とりあえず気にしない。
まぁ、そこはいい。


で、


なんでdrawTreeがTree String -> Stringなのかな?というところ。
そこは(Show a) => Tree a -> Stringだろ。
drawTreeで表示される木がなかなか奇麗なのがナオ悔しいところ。


あと、mapぐらい用意してくれ。

mapTree :: (a -> b) -> Tree a -> Tree b

ぐらい用意してくれ。
それさえあれば

showTree :: (Show a) => Tree a -> String
showTree = drawTree . mapTree show

で、drawTreeを一般化した(Show a) => Tree a -> Stringができるのに。


というわけで実装してみた

mapTree :: (a -> b) -> Tree a -> Tree b
mapTree f (Node label forest)	= Node (f label) $ map (mapTree f) forest

こんな感じか?


あと、unfoldがあってfoldがないのかいかがなものか、とfoldも実装。これであってるよね?

foldTree :: (a -> [b] -> b) -> Tree a -> b
foldTree f (Node label forest)	= f label $ map (foldTree f) forest

こうか?
多分これで、foldTree Nodeがid :: Tree a -> Tree aと恒等なはず。
Listのfoldも"foldr (:) []"が"id :: [a] -> [a]"な感じなんで、多分そう大きな間違いは無いはず。



...酔ってるんで色々間違いあるかと。
うーっぷす。