Opened 7 years ago

Closed 6 years ago

Last modified 20 months ago

#2850 closed feature request (fixed)

GeneralizedNewtypeDeriving + TypeFamilies doesn't work

Reported by: ajd Owned by:
Priority: normal Milestone: 6.12 branch
Component: Compiler Version: 6.10.1
Keywords: Cc: pumpkingod@…, dons@…
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case: indexed_types/should_compile/T2850
Blocked By: Blocking:
Related Tickets: Differential Revisions:

Description

It would be nice if we could do stuff like this:

{-# LANGUAGE GeneralizedNewtypeDeriving, TypeFamilies, FlexibleContexts, FlexibleInstances #-}
class K a where
  bar :: a -> a

class K (B a) => M a where
  data B a :: *
  foo :: B a -> B a

instance M Bool where
  data B Bool = B1Bool Bool | B2Bool Bool
  foo = id

instance K (B Bool) where
  bar = id

instance M Int where
  newtype B Int = BInt (B Bool) deriving K
  foo = id

which currently gives the error

foo.hs:17:41:
    Can't make a derived instance of `K (B Int)'
      (even with cunning newtype deriving:
       the newtype may be recursive)
    In the newtype instance declaration for `B'

However, the newtype is not recursive, it is just an associated datatype from another class, so it seems like this ought to work.

Change History (12)

comment:1 Changed 6 years ago by igloo

  • difficulty set to Unknown
  • Milestone set to 6.12 branch

comment:2 Changed 6 years ago by simonpj

cf #3046

comment:3 Changed 6 years ago by pumpkin

  • Cc pumpkingod@… dons@… added

comment:4 Changed 6 years ago by pumpkin

I find this error puzzling because this used to work in 6.8.3 and even (I believe) 6.10.1. But now I'm on 6.10.3 and am trying to compile some code that I hadn't touched since 6.10.1, and I get this error.

comment:5 Changed 6 years ago by simonpj

  • Resolution set to fixed
  • Status changed from new to closed
  • Test Case set to indexed_types/should_compile/T2850

Happily this seems OK in the HEAD (and hence 6.12). So I'll add a regression test and close the bug.

Simon

comment:6 Changed 21 months ago by nomeata

  • Type of failure set to None/Unknown

If we implement GND via Coercible, this will no longer work: Coercing bar :: B Bool -> B Bool to the instance for Int will print

      No instance for (GHC.Types.Coercible (B Bool) (B Int))
      because the first type argument of ‛B’ has role Nominal,
      but the arguments ‛Bool’ and ‛Int’ differ
      arising from a use of ‛GHC.Prim.coerce’

Richard, as the expert on roles, is that avoidable?

comment:7 Changed 20 months ago by goldfire

Interesting corner case.

Answer: perhaps, but it would take a little more engineering. The problem is that B's role is very rightly nominal. It's perfectly conceivable for B Age and B Int to be unrelated. But, we still want B Bool ~R B Int. The way this might be possible is by using the representation tycons for data families before doing the Coercible stuff. And, it means that these representation tycons would also need to be given appropriate roles. Currently, they're all nominal (see the source code).

This all seems quite possible, but as I said, somewhat more engineering to make work. I can take a look at inferring roles for data/newtype instances. (I suppose these means also making role signatures for these forms. Grrrr.....) Do you think it's possible for the Coercible stuff to work over representation tycons for data/newtype instances?

comment:8 Changed 20 months ago by nomeata

Ok, on second glance this seems to be just another instance of #8548, right? In that case, sorry for the noise.

comment:9 Changed 20 months ago by simonpj

Correct!! Solve #8548 and you are done.

comment:10 Changed 20 months ago by goldfire

Almost, but not quite, due to the lack of informative roles on data/newtype instance representation tycons. I do think the fix for #8548 would fix the example in this ticket, but not something like

data family D a
data instance D (Maybe a) = MkDMaybe a
class C (D (Maybe Int)) where ...
newtype instance D [a] = MkDList (D (Maybe a))
deriving instance C (D [Age])

That's all rather confusing, but I think it should work. And it would require informative roles on data/newtype instance representation tycons. These roles are currently all nominal.

Version 0, edited 20 months ago by goldfire (next)

comment:11 Changed 20 months ago by simonpj

Richard can you explain in more detail what "doesn't work2 in your example? Without the signatures of the class methods in C it's hard to makes sense of it.

comment:12 Changed 20 months ago by goldfire

As far as I can tell, my comment above (comment 10) is pure gibberish. There was a thought in my head somewhere, but every time I feel like I'm getting close to it, it runs away. Besides, after a little while trying, I was unable to come up with a relevant example. If there really is an issue here, we'll wait for someone to really hit it and yell. Otherwise, I'll move on.

Note: See TracTickets for help on using tickets.