
I thank Bertram Felgenhauer
class DShow a where dShows :: a -> String -> String instance DShow Char where dShows = showChar instance DShow Int where dShows = shows
instance DShow a => DShow [a] -- (1) where dShows _ = showString "contrived show value"
instance DShow String where dShows = shows -- (2)
f :: DShow a => [a] -> String f xs = dShows xs "" -- dShows (head xs) "" -- compare to this
main = putStr (shows (f "abc", f [1, 2, 3 :: Int]) "\n")
2. When GHC fails to select an instance among overlapping ones, it is often useful to report advice to the user: "consider adding such and such instance class assertion to a type context". For example, the user declares above f :: DShow a => [a] -> String, and the compiler advices to consider the declaration f :: (DShow a, DShow [a]) => [a] -> String. With this, the compiler postpones the instance selection in a client function (`main') for f. 2.1. Maybe, it is better for the compiler to automatically add such decls to the context, issue a warning and to continue compilation ? Because, evidently, the programmer presumes this declaration meaning. (?) 3. In my example with DShow, instance overlaps are really redundant. I looked into Prelude.Show, showList, and their usage in List and [Char]. I added an analogue of showList, and now DShow does not need overlapping instances. 4. But there are other situations, when it is much simpler for a programmer to declare overlapping instances than to apply tricks with additional class methods. 5. What the GHC developers think on my suggestion below with the user defined preference for overlapping instances? For any occasion, keep in mind, that sometimes I mistake. ------------------------------------------------------------------------ So, Bertram, (3) is the answer to your response of 19 Jan 2008
Does the trick from the Show class help you? Simplified, it is the following: class Show a where show :: a -> String showList :: [a] -> String [..]
We also wrote
3. Also DoCon uses overlapping instances, and works under ghc-6.8.2, somehow (probably, I need to recall what precisely this usage is).
You can fix your program by declaring
f :: DShow [a] => [a] -> String
or even
f :: (DShow a, DShow [a]) => [a] -> String
which will postpone the selection of the instance of DShow [a] to the point where f is called.
Yes, according to this your note, I suggest the point (2) in the abstract. This was my intention and expectation: I hope for the compiler to postpone, as possible, the instance selection. But it occurs that it needs a little help from the programmer. Probably, you answered by this why do i-overlaps work in DoCon. I recall, old GHC compilation reports adviced me to add the contexts similar to this `DShow [a]'. And I did add them. But in this example with DShow, ghc-6.8.2 does not advice this. I wonder what ghc-5.02.3 will report on this example. I have two large projects in Haskell + GHC. The current one is Dumatel -- a prover. It uses i-overlaps, but not essentially, as I see now, i-overlaps can easily be removed from it. The old project is DoCon -- computer algebra. I think, i-overlaps are essential in all application domains, but in computer mathematics they become visible somehow earlier.
There's only trouble with overlapping instances when you have several instances for the same type with different behaviour. (I don't know whether that's true or not for DoCon.)
Yes -- with different behaviour. It is true for DoCon, and this is
generally in-avoidable.
For an applied programmer, this sometimes occurs a natural way to
implement a method instance. And the compiler does have a certain
technical trouble. It must overcome it by posponing the instance
selection as possible. For example, in DoCon, I put
(example changed, it is contrived):
----------------------------------------------------------------------
class EuclideanRing a where divideWithRemainder :: a -> a -> a
...
class EuclideanRing a => Field a where ...
instance EuclideanRing IntegerModulo_2 where
divideWithRemainder a b = ...
instance Field IntegerModulo_2 where ...
instance :: EuclideanRing a => GCD (Polynomial a)
where
gcd f g = <generic method for greatest common divisor for polynomials>
instance GCD (Polynomial IntegerModulo_2)
where
gcd f g =

Serge, and others | 1. Can you check what ghc-5.02.3 will report on the below small program | with DShow I don't have ghc 5.02 to hand, but here's what 5.04.3 says about the code you give. ghc-5.04.3 -fglasgow-exts -fallow-overlapping-instances -fallow-undecidable-instances Serge.hs Serge.hs:14: Could not unambiguously deduce (DShow [a]) from the context (DShow a) The choice of (overlapping) instance declaration depends on the instantiation of `a' Probable fix: Add (DShow [a]) to the type signature(s) for `f' Or add an instance declaration for (DShow [a]) arising from use of `dShows' at Serge.hs:14 In the definition of `f': dShows xs "" | 2. When GHC fails to select an instance among overlapping ones, it is | often useful to report advice to the user: "consider adding such and | such instance class assertion to a type context". In general it's quite hard to make suggestions that are never misleading. In this case GHC does suggest something, but it's wrong! GHC 6.08's message is this: Serge.hs:14:23: Overlapping instances for DShow [a] arising from a use of `dShows' at Serge.hs:14:23-34 Matching instances: instance [overlap ok] (DShow a) => DShow [a] -- Defined at Serge.hs:(7,0)-(9,45) instance [overlap ok] DShow String -- Defined at Serge.hs:11:0-42 (The choice depends on the instantiation of `a' To pick the first instance above, use -fallow-incoherent-instances when compiling the other instance declarations) In the expression: dShows xs "" In the definition of `f': f xs = dShows xs "" This is better, although it does not suggest adding (DShow [a]) to the context of f. Adding that could perhaps be possible. | 3. In my example with DShow, instance overlaps are really redundant. | I looked into Prelude.Show, showList, and their usage in List and | [Char]. I added an analogue of showList, and now DShow does not need | overlapping instances. | | 4. But there are other situations, when it is much simpler for a | programmer to declare overlapping instances than to apply tricks with | additional class methods. I don't know what you are actually suggesting here | 5. What the GHC developers think on my suggestion below with the user | defined preference for overlapping instances? I believe your suggestion is: where instances overlap, choose the most specific. Yes, that's possible, and GHC does exactly that *unless* the answer to the match can be changed by instantiating a type variable. Consider f :: DShow a => a -> String If I need (DShow [a]) inside f, then you say, I guess, choose the DShow [a] instance even though there is a (DShow [Char]) instance. But if I changed 'f' to give it a more specific type: f :: Char -> String then we would choose the DShow [Char] instance instead. So making the type signature more specific has changed the semantics of the program. This is precisely what the flag -fallow-incoherent-instances does. So you can get the behaviour you ask for by giving an extra flag. Simon
participants (2)
-
Serge D. Mechveliani
-
Simon Peyton-Jones