-1

How can I write a generalized foldr function for generic Haskell trees?

data (Eq a, Show a) => Tree a = Void | Node a [Tree a]
    deriving (Eq, Show)

treefold :: (Eq a, Show a) => (a -> [b] -> b) ->  b -> Tree a -> b

I'm stuck at the first argument definition...

EDIT: what about a more generalized version, avoiding using lists? More here

Community
  • 1
  • 1
gremo
  • 47,186
  • 75
  • 257
  • 421
  • Can you explain what you mean by "first argument definition"? – sepp2k Feb 13 '11 at 01:24
  • @sepp2k: I mean `(a -> [b] -> b)` – gremo Feb 13 '11 at 01:28
  • @Gremo: That's the type of the first argument, yes. However I still don't know what you're having trouble with. I mean you already know the type of the first argument, so clearly your problem isn't what the type of the first argument should be. You're saying you're stuck at its "definition", but I really don't know what defining an argument means to you. I'm not trying to be difficult here, I just honestly don't know what you're asking. – sepp2k Feb 13 '11 at 01:31
  • @sepp2k: what I mean is, the first argument of treefold is a function and its signature is `(a -> [b] -> b)`. This function takes the first argument of type `a` (the same type of the tree), the second argument a list of types `b` and produces a type `b`. What is not clear to me is why the 2nd argument is a list of `b`. – gremo Feb 13 '11 at 02:14
  • @Gremo: It's a list because the function is meant to process the results for each of the subtrees. Since the number of subtrees is variable, this must be a list. If `Tree` was a binary the type of the first argument would probably be `a -> (b,b) -> b` or `a -> b -> b -> b`, i.e. it would take current node's value, the result of the left and the result of the right subtree. Since this is not a binary tree it instead takes a list containing the results of all the subtrees. – sepp2k Feb 13 '11 at 02:22
  • @sepp2k: that was clear enough, but why it is not `(a -> [a] -> a)`? – gremo Feb 13 '11 at 02:25
  • @Gremo the first argument is the "contents" of a given `Node`. The second argument is the *already folded* children of that `Node`... the function's job is to fuse the contents of the node with its folded children into a single folded value of type `b` – Tom Crockett Feb 13 '11 at 02:25
  • 1
    @Gremo: Because the result of the fold can have a different type than the contents of a tree. `a` is the type of the elements in the tree and `b` is the result type of the fold. So if you want to sum the lengths of a tree of strings, you'd pass in the function `\str subsums-> length str + sum subsums` and for each node it would call that function with the string inside the current node as well as the length-sums of the subtrees. The result of calling the function on the root node will be the result of the fold. – sepp2k Feb 13 '11 at 02:30

1 Answers1

1
data Tree a = Void | Node a [Tree a]
    deriving (Eq, Show)

The instance context is not necessary; deriving will do the right thing (creating instance (Eq a) => Eq (Tree a) and instance (Show a) => Show (Tree a)).

Your type signature looks just fine and is naturally implementable.

treefold :: (a -> [b] -> b) ->  b -> Tree a -> b
treefold _ k Void = k
treefold f k (Node a ts) = f a $ map (treefold f k) ts

See Data.Traversable for similar inspiration.

ephemient
  • 198,619
  • 38
  • 280
  • 391
  • Thank you for your answer. The solution seems to work, but I can't understand (I'm beginning Haskell) how map (which applies the function `treefold f k` to each element of the list) ends up with a single value, that is the last argument of `f a`... – gremo Feb 13 '11 at 01:49
  • @Gremo `ts :: [Tree a]` and `treefold f k :: Tree a -> b`, so `map (treefold f k) ts :: [b]` – Tom Crockett Feb 13 '11 at 02:12
  • 1
    @Gremo remember that `f :: a -> [b] -> b`, so the second argument has type `[b]`... it *produces* a single `b` – Tom Crockett Feb 13 '11 at 02:19