Tôi đang cố gắng viết một số mã Haskell trong đó có nhiều loại dữ liệu, mỗi loại có thể có nhiều triển khai. Để thực hiện điều này, tôi định nghĩa mỗi kiểu dữ liệu là class
có các phương thức là các hàm tạo và các bộ chọn có liên quan, và sau đó thực hiện tất cả các hoạt động trên các thành viên của lớp đó theo các hàm tạo và bộ chọn đã cho.Vui với các loại! Giải quyết nhiều khai báo cá thể
Ví dụ, có lẽ A
là một lớp đa thức (với các phương pháp getCoefficients
và makePolynomial
) mà có thể có một đại diện như một SparsePoly
hoặc một DensePoly
và B
là một lớp số phức tạp (với các phương pháp getReal
, getImag
và makeComplex
) có thể được được thể hiện dưới dạng ComplexCartesian
hoặc ComplexPolar
.
Tôi đã sao chép một ví dụ tối thiểu bên dưới. Tôi có hai lớp học A
và B
mỗi lớp đều có triển khai. Tôi muốn tự động tạo tất cả các phiên bản của cả hai lớp thành các phiên bản Num
(điều này yêu cầu các tiện ích mở rộng loại FlexibleInstances
và UndecidableInstances
). Đây hoạt động tốt khi tôi chỉ có một trong A
hoặc B
, nhưng khi tôi cố gắng biên dịch với cả hai, tôi nhận được lỗi sau:
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
Tôi cho rằng thông điệp của tờ khai dụ trùng lặp 'là bởi vì một kiểu dữ liệu có thể được tạo thành một phiên bản của cả hai A
và B
. Tôi muốn có thể hứa với trình biên dịch rằng tôi sẽ không làm điều đó, hoặc có thể chỉ định một lớp mặc định để sử dụng trong trường hợp một kiểu là một cá thể của cả hai lớp.
Có cách nào để thực hiện việc này (có thể là một loại tiện ích mở rộng khác không?) Hoặc đây có phải là điều tôi đang gặp phải không?
Dưới đây là mã của tôi:
{-# 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
Edit: Để làm cho bản thân mình rõ ràng, tôi không cố gắng để viết bất kỳ mã thực tế sử dụng kỹ thuật này. Tôi đang làm nó như một bài tập để giúp bản thân mình hiểu được hệ thống kiểu và phần mở rộng tốt hơn.
Liên quan: [Làm thế nào để viết, "nếu typeclass a, thì a cũng là một thể hiện của b theo định nghĩa này."] (Http://stackoverflow.com/a/3216937/98117). – hammar