4
\$\begingroup\$

Given the following algebraic data type, a Rose Tree:

data Tree a = Node {
 rootLabel :: a,
 subForest :: [Tree a]
} 

I attempted a foldTree function to fold over this list: (credit to this class's homework from 2013:

treeFold :: (b -> [b] -> b) -> (a -> b) -> Tree a -> b
treeFold f g tree = f (g (rootLabel tree)) (map (g . rootLabel) (subForest tree))

test

*Party> let tree = Node { rootLabel = 100, subForest = [] }
*Party> let tree2 = Node { rootLabel = 200, subForest = [tree] }
*Party> add tree2
300

Please review this implementation.

Given my definition of treeFold, I don't see how I could fold over a Tree Char, producing a [Char]/String result.

My understanding is that, for the return type, b, it can't be [a].

200_success
146k22 gold badges190 silver badges479 bronze badges
asked Nov 13, 2014 at 3:59
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

The implementation isn't correct, because it doesn't traverse sub-trees. Consider

Node 1 [Node 2 [Node 3 []]]

Then your folding function will only fold over 1 and 2, but not over 3.

If you have a recursive structure like this, a folding function over it must also be recursive. Otherwise it won't be able to traverse arbitrarily large recursive structure.

For the other question: If you specialize the folding function as

treeFold :: ([Char] -> [[Char]] -> [Char]) -> (Char -> [Char])
 -> Tree Char -> [Char]

by setting b = [Char], you get what you're looking for - converting a Tree Char to String. You just need to supply the two function for folding, for example

treeFold (\x ys -> x ++ concat ys) (: [])

Update: The signature also isn't correct. The general rule is that the folding function should have one additional argument for each constructor of the data type where recursive types (here Tree a) are replaced by the result of the fold:

treeFold :: (a -> [b] -> b) -> Tree a -> b

For example for a list you have 2 constructors: (:) :: a -> [a] -> [a] and [] :: [a], so its folding function is

foldr :: (a -> b -> b) -> b -> [a] -> b
answered Nov 13, 2014 at 8:05
\$\endgroup\$
4
  • \$\begingroup\$ Thank you, Petr. Does my function signature look right? \$\endgroup\$ Commented Nov 14, 2014 at 1:41
  • \$\begingroup\$ @KevinMeredith Updated. \$\endgroup\$ Commented Nov 14, 2014 at 12:28
  • \$\begingroup\$ Why isn't the correct signature's first argument: (a -> [b] -> b)? \$\endgroup\$ Commented Nov 14, 2014 at 12:40
  • \$\begingroup\$ @KevinMeredith You're absolutely right, I mixed up a and b. Of course, it must be the type of the result. Fixed. \$\endgroup\$ Commented Nov 14, 2014 at 16:01

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.