
Roman,
2014-02-10 18:22 GMT+01:00 Roman Cheplyaka
* Daniel Trstenjak
[2014-02-10 17:10:01+0100] On Mon, Feb 10, 2014 at 04:55:52PM +0100, Dominique Devriese wrote:
Hm. Interesting point, I guess this is the same problem as the whole orphan instances debate... I didn't think of the connection to that problem. Still, I'm convinced there are situations where local instances are *exactly* what we need, so there must be some way to avoid this problem...
If a type class has a clear semantical meaning, what should then be the point of having multiple instances for the same data type?
A clear semantical meaning contradicts multiple instances, they would only make reasoning about your code harder.
The few use cases where it might be nice to be able to define a new instance aren't IMHO worth the drawbacks.
You would just open Haskell for Ruby like monkey patching.
How about a compromise. We already have a way to introduce fresh type names: using existential types. They look like good candidates for local instances (by definition, they can't have global instances, because the names themselves are necessarily local). Of course, you can define an instance only once, as for usual types.
This would cover the case when "dynamic" instances are needed without compromising soundness. Example:
data IsoInt = forall a . IsoInt (Int -> a) (a -> Int)
foo modulus = case IsoInt id id of IsoInt (fromInt :: Int -> a) toInt -> let eqMod x1 x2 = (toInt x1 - toInt x2) `mod` modulus == 0
-- note: a is rigid here instance Eq a where (==) = eqMod in ...
Just a note that your proposal seems very related to what Kiselyov and Shan propose in their paper on "Implicit Configurations" (http://dl.acm.org/citation.cfm?id=1017481). Anyway, I still think that there are cases where I want to say that I want to use "real" local instances. Another interesting example by the way is instancing MonadState for IO. Consider how every IORef a can be used to build a MonadState a instance for IO: data MonadStateD a m = MonadStateD { putM :: a -> m (), getM :: m a } ioRefStateD :: IORef a -> MonadStateD a IO ioRefStateD ref = MonadStateD (writeIORef ref) (readIORef ref) I have the feeling that Brandon's argument (that multiple instances cannot be permitted because, for example, Data.Map should only be used with a single Ord instance) in some way comes down to solving a lack for an ML-like module system by imposing an otherwise artificial restriction on type classes: to enforce that a type class instance is unique within a module parameterised by it, we simply require that the instance be globally unique... That being said, Brendan is clearly right that we can't just drop a guarantee that is widely relied upon. Regards, Dominique