2

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.

1
  • 2
    I would guess that it's a typo and that the author meant the type you wrote, which is the correct recursor/catamorphism for BinTree. Commented Oct 13 at 20:09

1 Answer 1

5

If you've transcribed the requested type correctly, it's almost certainly an error in the book. Is it possible that your eye glossed over a b, and the type for foldTree was given this way?

foldTree :: (a -> b -> b -> b) -> b -> BinTree a -> b
--                      ^^^^^

In any case, your mapTree' (or some trivial rearrangement of it) is certainly the intended answer.

Sign up to request clarification or add additional context in comments.

1 Comment

Sadly no, the type signature in the book is as stated. I thought I would give this a couple of days but you 're probably right (you and Naïm Camille Favier both). I probably shouldn't sweat over it. I'm marking this one as solved. Thanks for your time!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.