Search code examples
haskellderivingnewtype

Deriving in newtype with more type variables


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?


Solution

  • 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).