假设我有以下代码:
{-# 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
字典。
答案 0 :(得分:5)
我希望GHC能够从
Typeable
构造函数的上下文中提取Wrap
约束
如果它有Wrap
构造函数,则可以从中提取Typeable
约束。
但它没有Wrap
构造函数。
不同之处在于Eq
实例使用了值,因此它是Wrap something
,其中Wrap
构造函数使得包装类型的Eq
字典可用,一切都很好,或者是⊥
,然后一切都很好,评估x == y
底部。
注意派生
instance Eq (Wrapper a)
不对类型变量Eq
有a
约束。
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)
自己。