我正在嘗試編寫一些Haskell代碼,其中有多個數據類型,每個數據類型都可以有多個實現。爲此,我將每個數據類型定義爲一個class
,其方法是相關的構造函數和選擇器,然後根據給定的構造函數和選擇器對該類的成員執行所有操作。有趣的類型!解決多個實例聲明
例如,也許A
是多項式類(方法getCoefficients
和makePolynomial
),其可以具有表示作爲SparsePoly
或DensePoly
和B
是複數類(方法getReal
,getImag
和makeComplex
),它可以是表示爲ComplexCartesian
或ComplexPolar
。
我已經複製了下面的一個簡單例子。我有兩個類A
和B
其中每個都有一個實現。我想要將這兩個類的所有實例自動分配到Num
的實例中(這需要FlexibleInstances
和UndecidableInstances
類型的擴展)。這工作得很好,當我只是有A
或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
編輯:爲了讓自己清楚,我不是要寫使用這種技術的任何實際的代碼。我正在做這個練習來幫助我更好地理解類型系統和擴展。
相關:[如何編寫,「如果類型類型a,則a也是此定義的b的一個實例。」](http://stackoverflow.com/a/3216937/98117)。 – hammar 2012-04-04 17:05:01