2016-07-24 15 views
1

私は作業中のタイプの型引数についてかなり複雑な条件を使用して型クリスタルのインスタンスを定義しようとしています。私が定義しているインスタンスの中から選択するクローズドタイプのファミリを宣言することになります。残念ながら、GHCはインスタンスが重複していると不満を表明するので、私はそのアイデアをまったく動かすことができません。ここで私が見ている同じエラーを与える簡単な例です:タイプファミリーを使用して、柔軟なコンテキストで重複するインスタンスを明確にしようとしているときにエラーが発生しました

{-# LANGUAGE FlexibleInstances, TypeFamilies #-} 
data MyContainer a = NoValue | OneValue a | TwoValues a a 

data Yes 
data No 

type family IsInt t where 
    IsInt Int = Yes 
    IsInt a = No 

instance IsInt t ~ Yes => Show (MyContainer t) where 
    show _ = "Type is int" 
instance IsInt t ~ No => Show (MyContainer t) where 
    show _ = "Type is not int" 

私が見ているエラーは次のとおりです。

src/Test.hs:11:10: 
    Duplicate instance declarations: 
     instance (IsInt t ~ Yes) => Show (MyContainer t) 
     -- Defined at src/Test.hs:11:10 
     instance (IsInt t ~ No) => Show (MyContainer t) 
     -- Defined at src/Test.hs:13:10 

どのように私は、オーバーラップインスタンスに頼らず(これらのインスタンスを明確にすることができますこのテストコードでは動作しますが、私のより複雑なオリジナルコードでは正しく動作していないようです)。

答えて

4

補助クラスで作業する必要があります。 ScopedTypeVariablesMultiParamTypeClassesUndecidableInstancesなどを有効にします。コードはまだテストされていません。あなたはまた、Noインスタンスを制約することができます

instance t ~ Int => Showy Yes t where 
    showy _ x = show (x + 22) 

のようなものでYesインスタンスを置き換えることで、好きならあなたが望むならあなたもIntを利用することができます

class Showy status t where 
    showy :: proxy status -> t -> String 

instance Showy Yes t where 
    showy _ _ = "yup" 

instance Showy No t where 
    showy _ _ = "nope" 

newtype S t = S t 
--Avoid overlapping unrelated `Show` instances. 
--This newtype would be unnecessary for a custom 
--class or when you're making instances for a 
--parameterized type already. 

instance (IsInt t ~ status, Showy status t) => Show (S t) 
    show (S t) = showy (Proxy :: Proxy status) t 

注:

instance Enum t => Showy No t where 
    showy _ = show . fromEnum 
+1

'Show t'インスタンスはすべての標準インスタンスと重複することに注意してください。 – chi

+1

@chi、それを修正しました。 – dfeuer

関連する問題