I've been making progress with Chris Allen's Haskell book and I am stumped in an exercise as the title suggests.
First of all, the binary tree is defined as such:
data BinTree a = Leaf | Node (BinTree a) a (BinTree a) deriving Show
A simple map function can be recursively defined for such a data structure, like this for example
mapTree :: (a -> b) -> BinTree a -> BinTree b
mapTree f Leaf = Leaf
mapTree f (Node lt k rt) = Node (mapTree f lt) (f k) (mapTree f rt)
however I am first asked to write a foldTree function with a type foldTree :: (a -> b -> b) -> b -> BinaryTree a -> b and write a map defined in terms of that foldTree function, which still eludes me.
I did my research of course, after trying and failing a few times, and stumbled upon this example foldTree with a slighlty different type (see Trying to Implement MapTree in terms of FoldTree)
foldTree :: (b -> a -> b -> b) -> b -> BinTree a -> b
foldTree f acc Leaf = acc
foldTree f acc (Node lt x rt) = f (foldTree f acc lt) x (foldTree f acc rt)
which is very convenient because the f function can handle the whole tree in one go, and then consume it (say for example foldTree (\lt x rt -> lt + x + rt) 0 sampleTree) if a catamorphism is what we want, or reconstruct it if the first argument is a Leaf, like so foldTree (\lt x rt -> Node lt x rt) Leaf sampleTree because the type of the first argument of f is also the output type. In fact, the ability to reconstruct the tree using foldTree is what allows the mapping function as an easy afterthought:
mapTree' :: (a -> b) -> BinTree a -> BinTree b
mapTree' f = foldTree (\lt x rt -> Node lt (f x) rt) Leaf
--> The actual question part:
Now, if the type of foldTree is what the book asks for, it seems very restrictive because the f function cannot deal with the whole tree at once, rather I have to 'chip away' at it branch by branch. I could for example do this:
foldTreeAlt :: (a -> b -> b) -> b -> BinTree a -> b
foldTreeAlt f acc Leaf = acc
foldTreeAlt f acc (Node Leaf x Leaf) = f x acc
foldTreeAlt f acc (Node lt x Leaf) = f x (foldTreeAlt f acc lt)
foldTreeAlt f acc (Node lt x rt) = foldTreeAlt f
(foldTreeAlt f acc rt)
(Node lt x Leaf)
which is fine for a catamorphism, say, a sum of the values if it's a BinTree Int, but I can't quite see how I can reconstruct the original tree the way I did with the first fold variant, thus how I can use it to implement map. It's probably something obvious but I can't figure it out. I get the idea that I have to really understand the solution to this before moving forward.
So if anyone has any input on this, I'd love to hear about it.
BinTree.