如何让GHC为上下文中具有Typeable的GADT生成Data.Typeable实例?

时间:2013-03-20 18:06:28

标签: haskell ghc gadt derived-instances

假设我有以下代码:

{-# LANGUAGE GADTs, DeriveDataTypeable, StandaloneDeriving #-}
import Data.Typeable

class Eq t => OnlyEq t
class (Eq t, Typeable t) => BothEqAndTypeable t

data Wrapper a where
    Wrap :: BothEqAndTypeable a => a -> Wrapper a

deriving instance Eq (Wrapper a)
deriving instance Typeable1 Wrapper

然后,以下实例声明起作用,没有约束t

instance OnlyEq (Wrapper t)

并做我期望它做的事。


但是以下实例声明不起作用:

instance BothEqAndTypeable (Wrapper t)

因为GHC - 我正在使用7.6.1 - 抱怨:

No instance for (Typeable t)
  arising from the superclasses of an instance declaration
Possible fix:
  add (Typeable t) to the context of the instance declaration
In the instance declaration for `BothEqAndTypeable (Wrapper t)'

当然,将Typeable t添加到上下文中。但添加以下实例也是如此:

instance Typeable (Wrapper t) where
    typeOf (Wrap x) = typeOf1 (Wrap x) `mkAppTy` typeOf x

有没有办法让GHC为我编写后一个实例?如果是这样,怎么样?如果没有,为什么不呢?

我希望GHC能够从Typeable构造函数的上下文中提取Wrap约束,就像它对Eq约束一样。 我认为我的问题可归结为GHC明确禁止撰写deriving instance Typeable (Wrapper t)这一事实,标准(Typeable1 s, Typeable a) => Typeable (s a)实例无法“查看”s a以找到Typeable a字典。

1 个答案:

答案 0 :(得分:5)

  

我希望GHC能够从Typeable构造函数的上下文中提取Wrap约束

如果它有Wrap构造函数,则可以从中提取Typeable约束。

但它没有Wrap构造函数。

不同之处在于Eq实例使用了值,因此它是Wrap something,其中Wrap构造函数使得包装类型的Eq字典可用,一切都很好,或者是,然后一切都很好,评估x == y底部。

注意派生

instance Eq (Wrapper a)

对类型变量Eqa约束。

Prelude DerivT> (undefined :: Wrapper (Int -> Int)) == undefined
*** Exception: Prelude.undefined
Prelude DerivT> (undefined :: (Int -> Int)) == undefined

<interactive>:3:29:
    No instance for (Eq (Int -> Int)) arising from a use of `=='
    Possible fix: add an instance declaration for (Eq (Int -> Int))
    In the expression: (undefined :: Int -> Int) == undefined
    In an equation for `it':
        it = (undefined :: Int -> Int) == undefined

Typeable实例不得使用该值,因此如果提供的值不是Wrap something,则不会触底。

因此派生的instance Typeable1 Wrapper提供

instance Typeable t => Typeable (Wrapper t)

但不是无约束的

instance Typeable (Wrapper t)

并且GHC不能导出无约束的实例。

因此,您必须提供约束

instance Typeable t => BothEqAndTypeable (Wrapper t)

或不受约束的

instance Typeable (Wrapper t)

自己。