我正在尝试编写一些 Haskell 代码,其中有多种数据类型,每种数据类型都可以有多个实现。为此,我将每个数据类型定义class
为其方法是相关的构造函数和选择器,然后根据给定的构造函数和选择器实现对该类成员的所有操作。
例如,也许A
是一个多项式类(带有方法getCoefficients
和makePolynomial
),可以表示为 aSparsePoly
或 a DensePoly
,并且B
是一个复数类(带有方法getReal
和) getImag
,makeComplex
可以表示为 aComplexCartesian
或 a ComplexPolar
。
我在下面复制了一个最小的例子。我有两个类A
,B
每个类都有一个实现。我想将两个类的所有实例都Num
自动转换为实例(这需要FlexibleInstances
和UndecidableInstances
类型扩展)。当我只有一个A
or时,这可以正常工作B
,但是当我尝试同时使用两者进行编译时,会出现以下错误:
Duplicate instance declarations:
instance [overlap ok] (A a, Num x, Show (a x), Eq (a x)) =>
Num (a x)
-- Defined at test.hs:13:10-56
instance [overlap ok] (B b, Num x, Show (b x), Eq (b x)) =>
Num (b x)
-- Defined at test.hs:27:10-56
我想“重复的实例声明”消息是因为数据类型可以同时成为A
和的实例B
。我希望能够向编译器承诺我不会这样做,或者可能指定一个默认类以在类型是两个类的实例的情况下使用。
有没有办法做到这一点(可能是另一种类型扩展?)或者这是我坚持的事情?
这是我的代码:
{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}
class A a where
fa :: a x -> x
ga :: x -> a x
data AImpl x = AImpl x deriving (Eq,Show)
instance A AImpl where
fa (AImpl x) = x
ga x = AImpl x
instance (A a, Num x, Show (a x), Eq (a x)) => Num (a x) where
a1 + a2 = ga (fa a1 + fa a2)
-- other implementations go here
class B b where
fb :: b x -> x
gb :: x -> b x
data BImpl x = BImpl x deriving (Eq,Show)
instance B BImpl where
fb (BImpl x) = x
gb x = BImpl x
instance (B b, Num x, Show (b x), Eq (b x)) => Num (b x) where
-- implementations go here
编辑:为了让自己清楚,我不想使用这种技术编写任何实用的代码。我这样做是为了帮助自己更好地理解类型系统和扩展。