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

Jul*_*les 2 haskell typeclass type-families

我试图在我正在使用的类型的类型参数上使用一些相当复杂的条件来定义类型类的实例,并且认为一个有用的方法是声明一个封闭的类型系列,该系列在我定义的实例之间进行选择。不幸的是,我根本无法让这个想法发挥作用,因为 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"
Run Code Online (Sandbox Code Playgroud)

我看到的错误是:

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
Run Code Online (Sandbox Code Playgroud)

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

dfe*_*uer 5

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

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
Run Code Online (Sandbox Code Playgroud)

请注意,您还可以使用Intif you like,将Yes实例替换为类似的内容

instance t ~ Int => Showy Yes t where
  showy _ x = show (x + 22)
Run Code Online (Sandbox Code Playgroud)

No如果您愿意,您还可以约束实例:

instance Enum t => Showy No t where
  showy _ = show . fromEnum
Run Code Online (Sandbox Code Playgroud)