Haskell 尝试使用类型族消除具有灵活上下文的重叠实例时出错

Haskell 尝试使用类型族消除具有灵活上下文的重叠实例时出错,haskell,typeclass,type-families,Haskell,Typeclass,Type Families,我试图使用我正在使用的类型的类型参数的一些相当复杂的条件来定义TypeClass的实例,我认为一种有用的方法是声明一个封闭类型族,在我正在定义的实例之间进行选择。不幸的是,我根本不能让这个想法起作用,因为GHC抱怨说这些实例是重复的。下面是一个简化的示例,它给出了与我看到的相同的错误: {-# LANGUAGE FlexibleInstances, TypeFamilies #-} data MyContainer a = NoValue | OneValue a | TwoValues a a

我试图使用我正在使用的类型的类型参数的一些相当复杂的条件来定义TypeClass的实例,我认为一种有用的方法是声明一个封闭类型族,在我正在定义的实例之间进行选择。不幸的是,我根本不能让这个想法起作用,因为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

如何在不使用重叠实例的情况下消除这些实例的歧义,这些重叠实例适用于此测试代码,但对于我更复杂的原始代码似乎无法正常工作?

您需要使用辅助类。启用ScopedTypeVariables、MultiparamTypeClass、UndededicatableInstances等。代码尚未测试

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
注意,如果愿意,还可以使用Int,方法是将Yes实例替换为

instance t ~ Int => Showy Yes t where
  showy _ x = show (x + 22)
如果愿意,还可以约束No实例:

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

你需要使用辅助类。启用ScopedTypeVariables、MultiparamTypeClass、UndededicatableInstances等。代码尚未测试

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
注意,如果愿意,还可以使用Int,方法是将Yes实例替换为

instance t ~ Int => Showy Yes t where
  showy _ x = show (x + 22)
如果愿意,还可以约束No实例:

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

请注意,Show t实例将与所有标准实例重叠。@chi,我已修复该问题。请注意,Show t实例将与所有标准实例重叠。@chi,我已修复该问题。