tags:

views:

185

answers:

3

I'm going through the problems in the Haskell O'Reilly book. The problem I am working on is

Using the binary tree type that we defined earlier in this chapter, write a function that will determine the height of the tree. The height is the largest number of hops from the root to an Empty. For example, the tree Empty has height zero; Node "x" Empty Empty has height one; Node "x" Empty (Node "y" Empty Empty) has height two; and so on.

I'm writing my code in a file called ch3.hs. Here's my code:

36 data Tree a = Node a (Tree a) (Tree a)
37             | Empty
38               deriving (Show)
39
40 --problem 9:Determine the height of a tree
41 height :: Tree -> Int
42 height (Tree node left right) = if (left == Empty && right == Empty) then 0 else max (height left) (height right) 

opening ghci in the terminal and typing :load ch3.hs. When I do that I get the following error:

Prelude> :load ch3.hs
[1 of 1] Compiling Main             ( ch3.hs, interpreted )

ch3.hs:42:7: Not in scope: data constructor `Tree'
Failed, modules loaded: none.

I expect that the Tree data constructor should be there, because I defined it in the lines above the height method. But when I try to load the file, I'm told that the data constructor is not in scope. I appreciate your help and explanation of why this error occurs. Thanks, Kevin

+6  A: 

Change

 height (Tree node left right) 

to

height (Node node left right)

I.e. the pattern matching works on the constructors of the algebraic data type. Tree is not a constructor, it is the name of the ADT.

Btw, you have to comment out your function signature declaration to compile the code, because it contains an error.

You can then check the inferred type via

:t height
maxschlepzig
Thanks, that worked. I still don't fully understand what's going on, and now getting errors at runtime, but will continue to stare and think and debug.
Kevin Burke
Another example might make it easier to understand. Let's pretend we are working with integers, not trees. Int is the name of the integer type. You can't add "Int + Int" because Int is the name of the type, not a constructor that returns a value of that type. Things like 0, 1, 2, ... are the constructors, and if you want to work with integers, that's how you get them into your program. Applying this to your case, `Tree` is the name of the type, and `Node` (or `Empty`) is how you get a value *of* that type.
jrockway
The HaskellWiki also has a helpful section, and it even uses Tree as the example: http://www.haskell.org/haskellwiki/Constructor
jrockway
+1  A: 

You pattern-match against constructors, i.e. the cases, of your Tree ADT. Tree is just what sums them all up.

It's much more straightforward like this, and, most of all, correct:

height Empty = 0
height (Node _ l r) = 1 + max (height l) (height r)
Dario
-1 This is wrong. Test with `height (Node 1 (Node 2 Empty Empty) (Node 3 Empty Empty))`. Should be 2, is 0 - it is 0 for any input, because of the same bug the OP has.
delnan
Thanks. I am still trying to get used to pattern matching. I marked the other answer correct because the question was about the data constructor but this is also helpful.
Kevin Burke
Fixed - need to add 1 to the value of max (height left) (height right) so it won't continue to return 0.
Kevin Burke
Sorry, of course we need the + 1.
Dario
+4  A: 

Your code is wrong, on several levels. It looks like you misunderstood algebraic data types.

  • The type signature is wrong, a Tree is always a Tree of a specific type - which you called a in its declaration, and which may be any type (since you didn't constraint it). So heigth has to take a Tree of some type - a Tree SomeType, too. You can and should use the most generic type for SomeType, i.e. a type variable like a.
  • When pattern matching, you name a specific constructor - Node a (Tree a) (Tree a) or Empty - to match against, not against the type as a whole. So height (Node ...) would match a Node, height (Empty) would match a Empty, and height (Tree ...) would try to match a constructor named Tree, but there is none. That's the error message you recieve.
  • You never ever compare (via ==) with a Constructor. It would actually work if you wrote deriving (Show, Eq). But you should use pattern matching to determine if you reached an Empty
  • Which leads to: You're only matching Node, not Empty - you should add a clause for Empty.
  • Also, your function still returns 0 for all inputs if you fix all the above issues. You never return anything but 0 or the max of the childrens' height - which can, in turn, only return 0 or the max of their childrens' height, etc ad infinitum. You have to increment the result at each level ;)
delnan
Thanks for the help. I just started a little while ago and am still getting used to the new language.
Kevin Burke
@Kevin if it helps, please upvote
delnan