I am writing a simple hash tree structure in the following program hash_lookup.hs
:
module Main where
data (Eq a) => HashTable a b = HashChildren (a, [HashTable a b]) | Hash (a, b) deriving (Show)
getKey :: HashTable a b -> a
getKey (HashChildren (k, hs)) = k
getKey (Hash (k, h)) = k
lookUp :: [a] -> HashTable a b -> Maybe (HashTable a b)
lookUp [] table = return table
lookUp _ (Hash _) = Nothing
lookUp (p:path) (HashChildren (_, ts) ) = lookUp path ( head ( dropWhile (\x -> (getKey x) /= p) ts ) )
getKey is intended to retrieve the root key of a given HashTable, and lookUp takes a list of strings and is meant to follow the first path it finds until it either reaches the full path or fails (I'm aware that this isn't natural behaviour for a tree but it's what my tutorial wants).
I have two questions:
1) Why do I get an error message telling me that a /= a
(from the final line) is not allowed as there is No instance for (Eq a)
(the error message in terminal), despite (Eq a)
in the data declaration?
2) Other than the error I'm getting and the seemingly strange behaviour of the lookup function, is this good or idiomatic Haskell?
Thanks
One of the common "gotchas" in Haskell is that if you put class constraints on a data
declaration, every function that uses the type must have the class constraints too. For this reason, your data
declaration is not idiomatic in Haskell, and you should eliminate its class constraint. It doesn't gain you anything to declare the class constraint in the data
declaration anyway.
Basically, function types must repeat the class constraint. How else is a user of the function to know that they must use an instance of the classes in question? Notice that you can have a function f
defined in terms of a function g
defined in terms of an h
that's defined in terms of your HashTable a b
type, such that f
doesn't mention your HashTable
type at all, yet because of the type dependencies it takes an argument of type a
that indirectly and ultimately is used as the first parameter of your HashTable
type. f
's type must have the class constraint, Haskell correctly infers so, and it will reject your type annotations if they lack it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With