Re: New to haskell: unresolved overloading question

Blair Fraser wrote:
I'm new to haskell and I'm working through the class section of the gentle tutorial. I decided to implement an ApproxEq class (just for fun), but have run into problems. The code below works fine for units and bools, but gives an unresolved overloading error for Floats and Doubles. What's going on here? What does the error message mean and what did I do wrong? (I'm in Hugs.)
-- ApproxEq: My first class. class (Eq a) => ApproxEq a where (~=) :: a -> a -> Bool x ~= y = x == y -- By default, check equality
-- These two override default with same, just checking if it works instance ApproxEq () where () ~= () = True instance ApproxEq Bool where x ~= y = x == y
-- These two override default with different -- consider floating points equal if they differ by one or less instance ApproxEq Float where x ~= y = (abs (x-y) <= 1) instance ApproxEq Double where x ~= y = (abs (x-y) <= 1)
More elegant seems to be: instance (Ord a, Num a) => ApproxEq a where x ~= y = (abs (x-y) < 1) However, this requires extensions to "Allow unsafe overlapping instances": hugs -98 +O ghci -fglasgow-exts -fallow-overlapping-instances -fallow-undecidable-instances -fallow-incoherent-instances
-- This one dosn't work either, but it just depends on the other two instance ApproxEq a => ApproxEq [a] where [] ~= [] = True (x:xs) ~= (y:ys) = x ~= y && xs ~= ys _ ~= _ = False
Thanks, Blair

There are problems with this approach... Instance heads are only chosen by the pattern not the constraints, so: instance (Ord a, Num a) => ApproxEq a where x ~= y = (abs (x-y) < 1) Will match any type at all (whether a member of Ord or Num or not) and then will fail if the particular type is not an instance of Ord or Num. Using incoherent-instances is almost certainly broken as it just stops the compiler complaining is a generic instance (like above) overlaps with a specific instance in the wrong way. Using the flag just makes GHC silently choose the _most_generic_instance_. Almost alwaysApproxEq we want the opposite behaviour and want GHC to choose the most specific instance in the case of overlap. However it should do what you want with just -foverlapping-instances -fundecidable-instances. Keean. Christian Maeder wrote
Blair Fraser wrote:
I'm new to haskell and I'm working through the class section of the gentle tutorial. I decided to implement an ApproxEq class (just for fun), but have run into problems. The code below works fine for units and bools, but gives an unresolved overloading error for Floats and Doubles. What's going on here? What does the error message mean and what did I do wrong? (I'm in Hugs.)
-- ApproxEq: My first class. class (Eq a) => ApproxEq a where (~=) :: a -> a -> Bool x ~= y = x == y -- By default, check equality
-- These two override default with same, just checking if it works instance ApproxEq () where () ~= () = True instance ApproxEq Bool where x ~= y = x == y
-- These two override default with different -- consider floating points equal if they differ by one or less instance ApproxEq Float where x ~= y = (abs (x-y) <= 1) instance ApproxEq Double where x ~= y = (abs (x-y) <= 1)
More elegant seems to be:
instance (Ord a, Num a) => ApproxEq a where x ~= y = (abs (x-y) < 1)
However, this requires extensions to "Allow unsafe overlapping instances":
hugs -98 +O
ghci -fglasgow-exts -fallow-overlapping-instances -fallow-undecidable-instances -fallow-incoherent-instances
-- This one dosn't work either, but it just depends on the other two instance ApproxEq a => ApproxEq [a] where [] ~= [] = True (x:xs) ~= (y:ys) = x ~= y && xs ~= ys _ ~= _ = False
Thanks, Blair
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Keean Schupke wrote:
There are problems with this approach...
instance (Ord a, Num a) => ApproxEq a where x ~= y = (abs (x-y) < 1)
However it should do what you want with just -foverlapping-instances -fundecidable-instances.
Only -fallow-incoherent-instances allowes to resolve 3.5 ~= 2.6 without type-annotations! But when adding: instance ApproxEq Double where x~=y = False the above result remained True (via Defaulting) whereas 3.5 ~= (2.6 :: Double) became False. (An the other hand there was no need to add such an instance for Double.) It is also not possible to add a further instance like: instance (Ord a, Fractional a) => ApproxEq a where x ~= y = (abs (x-y) < 0.1) (hoping that fractionals are treated more accurate that nums) Only one instance for "ApproxEq a" is allowed. Since the subject is "New to haskell" I recommend to stay Haskell98 compliant, i.e. avoid overlapping instances and add type signatures as necessary. If you add the option -Wall (or -fwarn-type-defaults) to ghci you'll get a warning whenever "defaulting" occurs (like in 1.5 == 1.5 to Double) (Putting "default ()" in your source file prevents defaulting, but I don't recommend to do so only to force types on decls like "f = 1.5") Christian

Am Montag, 21. Februar 2005 17:32 schrieb Christian Maeder:
Blair Fraser wrote:
I'm new to haskell and I'm working through the class section of the gentle tutorial. I decided to implement an ApproxEq class (just for fun), but have run into problems. The code below works fine for units and bools, but gives an unresolved overloading error for Floats and Doubles. What's going on here? What does the error message mean and what did I do wrong? (I'm in Hugs.)
-- ApproxEq: My first class. class (Eq a) => ApproxEq a where (~=) :: a -> a -> Bool x ~= y = x == y -- By default, check equality
-- These two override default with same, just checking if it works instance ApproxEq () where () ~= () = True instance ApproxEq Bool where x ~= y = x == y
-- These two override default with different -- consider floating points equal if they differ by one or less instance ApproxEq Float where x ~= y = (abs (x-y) <= 1) instance ApproxEq Double where x ~= y = (abs (x-y) <= 1)
More elegant seems to be:
instance (Ord a, Num a) => ApproxEq a where x ~= y = (abs (x-y) < 1)
However, this requires extensions to "Allow unsafe overlapping instances":
hugs -98 +O
ghci -fglasgow-exts -fallow-overlapping-instances -fallow-undecidable-instances -fallow-incoherent-instances
-- This one dosn't work either, but it just depends on the other two instance ApproxEq a => ApproxEq [a] where [] ~= [] = True (x:xs) ~= (y:ys) = x ~= y && xs ~= ys _ ~= _ = False
Thanks, Blair
For the original code, no extensions are necessary (and neither hugs nor ghc does complain). Probably something like ApproxEq> 1.5 ~= 2.4 ERROR - Unresolved overloading *** Type : (Fractional a, ApproxEq a) => Bool *** Expression : 1.5 ~= 2.4 happened, that doesn't mean there is any problem with the code, only that the interpreter doesn't know what type 1.5 and 2.4 have. Adding a type to either resolves: ApproxEq> 1.5 ~= (2.4::Double) True ApproxEq> [1,2,3] ~= [1.6,2.8,3.9999] ERROR - Unresolved overloading *** Type : (Fractional a, ApproxEq a) => Bool *** Expression : [1,2,3] ~= [1.6,2.8,3.9999] ApproxEq> [1,2,3] ~= ([1.6,2.8,3.9999]::[Float]) True That's a very common problem for newbies, so don't panic. In older versions of hugs (November 2002, e.g.), you would have got an unresolved overloading also from entering [] to the prompt (this is no longer so). If such things happen, add an explicit typing, if that doesn't help, then you have a problem. To deepen the confusion, hugs has no problems with Prelude> 1.5 == 1.5 True I'm not quite sure why this works, must be due to type defaulting, however, including default (Double) doesn't help ApproxEq, so there must be more to it in the (==) case. BTW, if you add Christian's instance, for hugs, -98 +o (lower case o, allow overlapping instances) suffices, for ghci, -fallow-incoherent-instances is not necessary. Stay with Haskell, it's great (though not perfect)! Daniel

Am Dienstag, 22. Februar 2005 00:34 schrieb Daniel Fischer: <snip>
That's a very common problem for newbies, so don't panic. In older versions of hugs (November 2002, e.g.), you would have got an unresolved overloading also from entering [] to the prompt (this is no longer so). If such things happen, add an explicit typing, if that doesn't help, then you have a problem.
To deepen the confusion, hugs has no problems with
Prelude> 1.5 == 1.5 True
I'm not quite sure why this works, must be due to type defaulting, however,
Ah, I found out, carefully rereading the pertinent paragraph of the report (4.3.4) informed me that, for the defaulting rules to be applied, *all Classes in the context must be defined in the Prelude or the standard libraries*, which of course ApproxEq isn't. If you include default () or default (Integer) in your script, 1.5 == 2.4 will also lead to an unresolved overloading, so defaulting really works. Bye for now, Daniel
participants (3)
-
Christian Maeder
-
Daniel Fischer
-
Keean Schupke