问题
data Tree a = Leaf | Node (Tree a) a (Tree a) deriving (Eq, Show)
unfoldTree:: (b -> Maybe (b, a, b)) -> b -> Tree a
unfoldTree f b =
case f b of
Nothing -> Leaf
Just (lt, x, rt) -> Node (unfoldTree f lt) x (unfoldTree f rt)
Given the two piece of information above, I'm asked to implement a tree building function.
and my attempt is
treeBuild :: Integer -> Tree Integer
treeBuild 0 = Leaf
treeBuild n = treeUnfold (\b -> if b < 2^n-1
then Just(2*b, b + 1, 2*b + 1)
else Nothing)
0
The base case works where n = 0 works fine but I know the function is completely wrong. Can someone re-explain to me how would a 3-tuple Just
work? In a normal unfold, the first element in a Just
would be the element I want and the second element would be used to continue unfolding but how does this work in a 3-tuple Just?
As example output:
treeBuild 2 ----> Node (Node Leaf 0 Leaf) 1 (Node Leaf 2 Leaf)
Edit:
I'm not completely sure how Just works here, for the case of Just(2*b, b + 1, 2*b + 1)
where b starts at 0, does it become Just(0, 1, 0)
? How do I actually increment b?
回答1:
I think you omitted a space when pasting the definition of unfoldTree
. Should it be this?
unfoldTree f b = case f b of ...
There's nothing intrinsically meaningful about Maybe (b, a, b)
, but in this particular case you can see that unfoldTree
binds the items in the tuple to lt
, x
, and rt
. The middle value x
is used to create a node, and lt
and rt
are used to seed the recursive calls to unfoldTree
.
To explain your example output, note that n
is always bound to 2
. The initial 0
argument to treeUnfold
means the (\b -> ...)
function first checks 0 < 2^n-1
, then yields Just (2*0, 0+1, 2*0+1)
.
The middle value, 0+1
is the value of the root node in your tree. The left subtree is built similarly except b
is now 2*0
, and the right subtree is built with b
as 2*0+1
.
You mention this is homework which is supposed to build a tree with 2^n - 1
nodes. I'm going to guess that Leaf
values don't count and that you want to number these nodes in breadth-first order, and hopefully this example gets you in the neighborhood. Here's how to do that:
treeBuild :: Int -> Tree Int treeBuild n = treeUnfold (\b -> if b < 2^n - 1 then Just (2*b+1, b, 2*b+2) else Nothing) 0
The way I arrived at this is by drawing a binary tree with depth 3. I numbered the nodes starting with the root as 0
, the left node as 1
and the right node as 2
. The bottom nodes are numbered from left to right starting with 4
and ending at 7
.
Now the pattern is visible: if the current node is numbered b
, his left and right nodes are numbered 2*b+1
and 2*b+2
respectively. Since 2^n - 1
is the total number of nodes in a tree of depth n
, and I'm numbering nodes in breadth-first order, returning Nothing
when b >= 2^n-1
ensures I stop after filling the tree up to depth n
.
来源:https://stackoverflow.com/questions/15538151/tree-building-function-in-haskell-homework