A):
mapLabel :: Eq a => (a -> b) -> Tree a -> Tree b
Node label []) = Node (f label) []
mapLabel f (Node label subTrees) = (Node (f label) (subLeaves subTrees))
mapLabel f (where subLeaves [] = []
:ts)
subLeaves (t| leaf t = Node (f label) [] : subLeaves ts
| otherwise = Node (f label) (subLeaves subTrees) : subLeaves ts
B):
fmap f (Node x ts) = Node (f x) (map (fmap f) ts)
The idea was to create a function that would walk through a tree-like data structure and do some stuff to it. First I spent 2 evenings designing (or understanding rather) a recursive patter-matching function. The evening I was able to compile it and produce the expected result – I felt quite content with myself…
C):
mapLabel :: Eq a => (a -> b) -> Tree a -> Tree b
Node label []) = Node (f label) []
mapLabel f (Node label subTrees) = (Node (f label) (subLeaves subTrees))
mapLabel f (where subLeaves [] = []
:ts)
subLeaves (t| leaf t = Node (f label) [] : subLeaves ts
| otherwise = Node (f label) (subLeaves subTrees) : subLeaves ts
where label = rootLabel t
Just look at the awe-inspiring complexity of it!.. How is it even possible that my humble mind was able to grasp that? Then I revisited some of the related source-code inside Data.Tree module:
D):
instance Functor Tree where
fmap f (Node x ts) = Node (f x) (map (fmap f) ts)
… So much for the awesome complexity. It turned out the the solution B) is functionally equivalent to A) and has additional benefit of being so much more concise and easy to re-factor into, say, this:
fmap f (Node x ts) = Node (f ts) (map (fmap f) ts)
(This function will recursively operate on ts (pattern-matched to subForest members), rather than on the x (rootLabel), as in the function above, without loosing readability – ain’t that just peachy?):
Further example of the same principle:
-- A and B are roughly equivalent:
-- A:
gamma :: Tree String -> Tree String -> Tree Int
= Node a forest
gamma t k where a = (\[x, y] -> x*y) $ map read $ map rootLabel [t,k]
= (multIntForests (subForest t) (subForest k))
forest
multIntTrees :: Tree String -> Tree String -> Tree Int
= gamma
multIntTrees
multIntForests :: [Tree String] -> [Tree String]-> [Tree Int]
= []
multIntForests [] _ = []
multIntForests _ [] :ts) (k:ks) = gamma t k : multIntForests ts ks
multIntForests (t
-- B:
Node a ts) (Node b ks) = (Node (f a b) (zipWith (delta f) ts ks)) delta f (
… And more examples:
-- A and B are equivalent:
-- A:
-- Aquire a tree with the number of sub-nodes as a value of the rootLabel:
members :: Tree String -> Tree String
Node x []) = Node {rootLabel = "0", subForest = []}
members (Node x ts0) = Node {rootLabel = (show $ length ts0), subForest = subNodes ts0}
members (where subNodes [] = []
= members t : []
subNodes [t] :ts) = (members t): subNodes ts
subNodes (t
-- B:
members :: Tree String -> Tree String
= fmap length members