我试图在我正在使用的类型的类型参数上使用一些相当复杂的条件来定义类型类的实例,并且认为一个有用的方法是声明一个封闭的类型系列,该系列在我定义的实例之间进行选择。不幸的是,我根本无法让这个想法发挥作用,因为 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
, MultiParamTypeClasses
, UndecidableInstances
, 等等。代码尚未测试。
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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)