3
newtype MyNewtype1 f v = MyNewtype1 { getVal1 :: f v } deriving Eq -- OK
newtype MyNewtype2 f maybe v = MyNewtype2 { getVal2 :: f (maybe v) } deriving Eq --OK
newtype MyNewtype3 f v = MyNewtype3 { getVal3 :: f (Maybe v) } --  OK
newtype MyNewtype4 f v = MyNewtype4 { getVal4 :: f (Maybe v) } deriving Eq --NOT OK

I have these newtypes. The first three work as expected, but the fourth gives:

    • No instance for (Eq (f (Maybe v)))
        arising from the 'deriving' clause of a data type declaration
      Possible fix:
        use a standalone 'deriving instance' declaration,
          so you can specify the instance context yourself
    • When deriving the instance for (Eq (MyNewtype4 f v))

I can't understand where is the problem. It seems to me, that the second newtype is strictly more general and thus have to suffer the same problem. So if MyNewtype2 can derive Eq, why MyNewtype2 can not? That's probably what confuses me the most. Could somebody please explain this to me? Also, what is the preferred solution to if I want a newtype like that?

user1747134
  • 2,374
  • 1
  • 19
  • 26

2 Answers2

4

I don't know why 2 works but 4 doesn't. Probably has something to do with flexible contexts (which I don't understand well enough to explain).

To answer the second question... the preferred solution if you want a newtype like that is as GHC suggested: to use a standalone deriving instance.

{-# LANGUAGE StandaloneDeriving, FlexibleContexts, UndecidableInstances #-}

newtype MyNewtype4 f v = MyNewtype4 { getVal4 :: f (Maybe v) }
deriving instance (Eq (f (Maybe v))) => Eq (MyNewtype4 f v)
leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
  • Thanks, I did not know the standalone deriving syntax. I am still interested, why 2 works. – user1747134 Sep 08 '16 at 12:08
  • 1
    The specific rule in the documentation says "The rule is this: each constraint in the inferred instance context must consist only of type variables, with no repetitions." Apparently `Eq (f (maybe v))` qualifies`. – Alexey Romanov Sep 08 '16 at 15:09
  • @AlexeyRomanov, that seems ... surprising. Am I correct in thinking that `FlexibleContexts` is an unintrusive extension that really just simplifies everything? Or does it have some unfortunate consequences like (some aspects of) `FlexibleInstances`? – dfeuer Sep 08 '16 at 17:37
  • I've undeleted my answer, since I found why 4 isn't allowed (I think). – Alexey Romanov Sep 08 '16 at 18:03
3

The third [generated instance] is not Haskell 98, and risks losing termination of instances. GHC takes a conservative position: it accepts the first two, but not the third. The rule is this: each constraint in the inferred instance context must consist only of type variables, with no repetitions. This rule is applied regardless of flags. If you want a more exotic context, you can write it yourself, using the standalone deriving mechanism.

I think MyNewType4 is considered unsafe and so not allowed to be derived because it violates the second Paterson condition:

2.The constraint has fewer constructors and variables (taken together and counting repetitions) than the head

MyNewtype4 f v has 3, and so does f (Maybe v). MyNewtype2 f maybe v has 4, and so instance (Eq (f (maybe v))) => MyNewtype2 f maybe v obeys the condition (and so does any case following the rule quoted at the beginning).

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • OK, but then what is the reason that the same error is raised even with -XUndecidableInstances? – user1747134 Sep 09 '16 at 09:42
  • That's the sentence I didn't quote at the beginning: "This rule is applied regardless of flags". They consider it unsafe enough that it should appear explicitly in code, so that if you do run into problems with termination you can more easily find it. – Alexey Romanov Sep 09 '16 at 10:46