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

我有这些新类型。前三个按预期工作,但第四个给出:

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

我不明白问题出在哪里。在我看来,第二种新类型严格来说更一般,因此必须遇到同样的问题。那么如果MyNewtype2能推导出Eq,为什么MyNewtype2不能呢?这可能是最让我困惑的地方。有人可以向我解释一下吗?另外,如果我想要这样的新类型,首选的解决方案是什么?

4

2 回答 2

4

我不知道为什么 2 有效,但 4 无效。可能与灵活的上下文有关(我不太了解,无法解释)。

要回答第二个问题...如果您想要像 GHC 建议的那样的新类型,首选的解决方案是:使用独立的派生实例。

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

newtype MyNewtype4 f v = MyNewtype4 { getVal4 :: f (Maybe v) }
deriving instance (Eq (f (Maybe v))) => Eq (MyNewtype4 f v)
于 2016-09-08T11:51:47.553 回答
3

第三个 [生成的实例] 不是 Haskell 98,并且有失去实例终止的风险。GHC 采取保守的立场:它接受前两个,但不接受第三个。规则是这样的:推断的实例上下文中的每个约束必须只包含类型变量,不能重复。无论标志如何,都会应用此规则。如果你想要一个更奇特的上下文,你可以自己编写,使用独立的派生机制。

我认为MyNewType4被认为是不安全的,因此不允许派生,因为它违反了第二个帕特森条件:

2.约束的构造函数和变量(一起计算重复次数)比头部少

MyNewtype4 f v有 3, 也有f (Maybe v)MyNewtype2 f maybe v有 4,所以instance (Eq (f (maybe v))) => MyNewtype2 f maybe v遵守条件(遵循开头引用的规则的任何情况也是如此)。

于 2016-09-08T15:00:01.177 回答