Reputation: 165
Trying to use the given fold function to flatten out a tree into a list.
treeFold :: (b -> a -> b -> b) -> b -> Tree a -> b
treeFold _ b Leaf = b
treeFold f b (Node lt x rt) = f (treeFold f b lt) x (treeFold f b rt)
Here is what I have tried to so far:
treeToList :: Tree a -> [a]
treeToList = treeFold (\xs x ys -> xs ++ x : ys) (\x -> [x])
For some reason, I can't quite wrap my head around how to go about doing this? Feels like there's something I haven't quite gotten into my head about Haskell. Any help would be appreciated along with how to go about solving it. Thanks!
Edit:
I realize that the type signature I am using here verges on the nonsensical. In the type signature of treeFold, based on what I can think, the second argument (b) is probably a list since it acts as the accumulator in a way in this case. That would make the third argument (Tree a) a some version of the argument on the left of the equation. Two of the arguments within the function have to be the left and right subtrees within a Node. The third argument is just the value of the Node. Within the function, I need to combine the left tree, right tree and the value in the usual in order fashion but all the different variations I tried have had some issues
Upvotes: 2
Views: 543
Reputation: 71070
The types must fit:
treeFold :: ( b -> a -> b -> b ) -> b -> Tree a -> b
treeToList = treeFold (\xs x ys -> xs ++ (x : ys)) z
-------------------------------------------------------------------
b a b b a b b
--------
b
Since x
and ys
participate in the same :
, their types must be compatible:
(:) :: a -> [a] -> [a]
x :: a
ys :: b
-------------------
b ~ [a]
Thus we have
treeFold :: ( [a] -> a -> [a] -> [a] ) -> [a] -> Tree a->[a]
treeToList = treeFold (\ xs x ys -> xs ++ (x : ys)) z
-------------------------------------------------------------------
[a] a [a] [a] a [a] [a]
--------
[a]
Conclusion: the last argument, z
, must have the type [a]
.
What is the meaning of this argument? As usual with the folds, each "variant" in the data type definition has a corresponding argument to the fold function.
Your (missing) data type definition is:
data Tree a = Node (Tree a) a (Tree a) | Leaf
and the fold's type is
treeFold :: ( b -> a -> b -> b ) -> b -> Tree a -> b
which corresponds to the "recursive results-holding type" of
data TreeF a r = NodeF r a r | LeafF
Thus z
is "the value to convert each Leaf
to".
Most natural choice for it is just []
. Actually, the only choice, because we don't know anything about the type a
(in [a]
) yet.
Upvotes: 4
Reputation: 85757
The type of treeFold
is
treeFold :: (b -> a -> b -> b) -> b -> Tree a -> b
You want to return a list of values, [a]
.
Therefore the result type b
must be equal to [a]
, giving us a specialized type signature of
treeFold :: ([a] -> a -> [a] -> [a]) -> [a] -> Tree a -> [a]
Note that the second argument has type [a]
.
What value are you passing instead?
Upvotes: 4