Overlapping instances problem

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Baa
Reply | Threaded
Open this post in threaded view
|

Overlapping instances problem

Baa
Hello, List!

I got error:

 Duplicate instance declarations:
   instance [overlap ok] EnumTag a => Read a
     -- Defined at /XXX/intero/intero2932Xpa-TEMP.hs:110:27
   instance [overlap ok] StrTag a => Read a
     -- Defined at /XXX/intero/intero2932Xpa-TEMP.hs:121:27 (intero)

For this code:

  class (Show a, Enum a) => EnumTag a where
    anyEnum :: a

  instance {-# OVERLAPS #-} EnumTag a => Read a where
    readPrec = RP.lift P.skipSpaces >> expectEnum
  instance {-# OVERLAPS #-} EnumTag a => Eq a where
    a == b | a == anyEnum || b == anyEnum = True
          | otherwise = fromEnum a == fromEnum b

  class StrTag a where
    anyStr :: a
    tagPrefix :: a -> String -- ^ should be constant
    toStr :: String -> a

  instance {-# OVERLAPS #-} StrTag a => Read a where
    readPrec = parens $ do
      RP.lift P.skipSpaces
      (RP.lift $ expectShown anyStr) <++ RP.lift g
      where g = do
              Just s@(_:_) <- L.stripPrefix tagPrefix <$> expectTag
              return $ toStr s

Why does it happen? `Read a` in 1st instance is valid only when a is
`EnumTag`, in 2nd one - is valid only when a is `StrTag`.

How can I fix this error and to create "default" instances for `EnumTag`
and to `StrTag`, so client code will "inherit" those functionality
(`Read`) simple, only with instantiation of `EnumTag` or `StrTag` ?

Sure, if I comment `instance ... StrTag a` then all work fine, but I need 2 specialized `Read`s (and `Eq`s too :)

===
Best regards, Paul
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Overlapping instances problem

David McBride
What happens if type 'a' is both an instance EnumTag and StrTag at the same time?  Then which instance does it choose?  You may know that can't happen in your code, but there's no guarantee that someone using your library or that some import won't bring such a type into scope.

Because of this ambiguity, during type checking haskell ignores class contexts and merely looks at the instance head (Read a), and says hey there are two instances 'Read a', they are overlapping.

As to what to do about it, I'm not sure.  But I don't think I would be trying to get different read instances based on whatever typeclasses happen to be in scope for that type.

On Fri, Dec 1, 2017 at 6:57 AM, Baa <[hidden email]> wrote:
Hello, List!

I got error:

 Duplicate instance declarations:
   instance [overlap ok] EnumTag a => Read a
     -- Defined at /XXX/intero/intero2932Xpa-TEMP.hs:110:27
   instance [overlap ok] StrTag a => Read a
     -- Defined at /XXX/intero/intero2932Xpa-TEMP.hs:121:27 (intero)

For this code:

  class (Show a, Enum a) => EnumTag a where
    anyEnum :: a

  instance {-# OVERLAPS #-} EnumTag a => Read a where
    readPrec = RP.lift P.skipSpaces >> expectEnum
  instance {-# OVERLAPS #-} EnumTag a => Eq a where
    a == b | a == anyEnum || b == anyEnum = True
          | otherwise = fromEnum a == fromEnum b

  class StrTag a where
    anyStr :: a
    tagPrefix :: a -> String -- ^ should be constant
    toStr :: String -> a

  instance {-# OVERLAPS #-} StrTag a => Read a where
    readPrec = parens $ do
      RP.lift P.skipSpaces
      (RP.lift $ expectShown anyStr) <++ RP.lift g
      where g = do
              Just s@(_:_) <- L.stripPrefix tagPrefix <$> expectTag
              return $ toStr s

Why does it happen? `Read a` in 1st instance is valid only when a is
`EnumTag`, in 2nd one - is valid only when a is `StrTag`.

How can I fix this error and to create "default" instances for `EnumTag`
and to `StrTag`, so client code will "inherit" those functionality
(`Read`) simple, only with instantiation of `EnumTag` or `StrTag` ?

Sure, if I comment `instance ... StrTag a` then all work fine, but I need 2 specialized `Read`s (and `Eq`s too :)

===
Best regards, Paul
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners


_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Baa
Reply | Threaded
Open this post in threaded view
|

Re: Overlapping instances problem

Baa
Thanks, I got it. So I workarounded the problem with newtypes (all
"default" instances are for newtypes, my types are wrapping in those
newtypes).

===
Best regards, Paul

> What happens if type 'a' is both an instance EnumTag and StrTag at
> the same time?  Then which instance does it choose?  You may know
> that can't happen in your code, but there's no guarantee that someone
> using your library or that some import won't bring such a type into
> scope.
>
> Because of this ambiguity, during type checking haskell ignores class
> contexts and merely looks at the instance head (Read a), and says hey
> there are two instances 'Read a', they are overlapping.
>
> As to what to do about it, I'm not sure.  But I don't think I would be
> trying to get different read instances based on whatever typeclasses
> happen to be in scope for that type.
>
> On Fri, Dec 1, 2017 at 6:57 AM, Baa <[hidden email]> wrote:
>
> > Hello, List!
> >
> > I got error:
> >
> >  Duplicate instance declarations:
> >    instance [overlap ok] EnumTag a => Read a
> >      -- Defined at /XXX/intero/intero2932Xpa-TEMP.hs:110:27
> >    instance [overlap ok] StrTag a => Read a
> >      -- Defined at /XXX/intero/intero2932Xpa-TEMP.hs:121:27 (intero)
> >
> > For this code:
> >
> >   class (Show a, Enum a) => EnumTag a where
> >     anyEnum :: a
> >
> >   instance {-# OVERLAPS #-} EnumTag a => Read a where
> >     readPrec = RP.lift P.skipSpaces >> expectEnum
> >   instance {-# OVERLAPS #-} EnumTag a => Eq a where
> >     a == b | a == anyEnum || b == anyEnum = True
> >           | otherwise = fromEnum a == fromEnum b
> >
> >   class StrTag a where
> >     anyStr :: a
> >     tagPrefix :: a -> String -- ^ should be constant
> >     toStr :: String -> a
> >
> >   instance {-# OVERLAPS #-} StrTag a => Read a where
> >     readPrec = parens $ do
> >       RP.lift P.skipSpaces
> >       (RP.lift $ expectShown anyStr) <++ RP.lift g
> >       where g = do
> >               Just s@(_:_) <- L.stripPrefix tagPrefix <$> expectTag
> >               return $ toStr s
> >
> > Why does it happen? `Read a` in 1st instance is valid only when a is
> > `EnumTag`, in 2nd one - is valid only when a is `StrTag`.
> >
> > How can I fix this error and to create "default" instances for
> > `EnumTag` and to `StrTag`, so client code will "inherit" those
> > functionality (`Read`) simple, only with instantiation of `EnumTag`
> > or `StrTag` ?
> >
> > Sure, if I comment `instance ... StrTag a` then all work fine, but
> > I need 2 specialized `Read`s (and `Eq`s too :)
> >
> > ===
> > Best regards, Paul
> > _______________________________________________
> > Beginners mailing list
> > [hidden email]
> > http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
> >  

_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners