[Haskell-cafe] manage effects in a DSL
Dominique Devriese
dominique.devriese at cs.kuleuven.be
Mon Feb 10 19:07:37 UTC 2014
Roman,
2014-02-10 18:22 GMT+01:00 Roman Cheplyaka <roma at ro-che.info>:
> * Daniel Trstenjak <daniel.trstenjak at gmail.com> [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
More information about the Haskell-Cafe
mailing list