
Ralf Lammel wrote:
As Bulat points out, the GHC primitive dataToTag# indeed nicely solves the problem. Ben, just for completeness' sake; with SYB, you get such reflective information too (and others):
shallowEq :: Data a => a -> a -> Bool shallowEq x y = toConstr x == toConstr y
(dataToTag# returns Int, while toConstr comprises other things like the constructor name.)
Ralf, Yes, I ended up using the "propper" SYB approach instead, though I have noticed that the reflection data types Constr and DataRep make no mention of type variables or functions. For example, this works fine:
getTag (Just 5) ==# getTag (Just{}) getTag (Just (\x -> x)) ==# getTag (Just{})
But this does not
toConstr (Just 5) == toConstr (Just{}) Ambiguous type variables.
toConstr (Just (\x -> x)) == toConstr (Just{}) No instance for Data (t -> t)
I appreciate the reasons why this is so, though I think it's interesting to see the practical consequences. A toConstr version of shallowEq works ok so long as you provide a type signature to constrain both arguments to be the same type, and one of them is always fully constructed - which is fine for me at the moment. Ben.