Bạn có thể thực hiện việc này tương đối rõ ràng và hiệu quả bằng cách sử dụng generic programming support của GHC 7.4. documentation for GHC.Generics có thể hữu ích. Đây là một ví dụ.
Hãy xem xét ví dụ sau lớp và một số trường hợp mẫu:
class C a where
-- | Double all numbers
double :: a -> a
instance C Int where
double i = 2 * i
instance (C a, C b) => C (a, b) where
double (a, b) = (double a, double b)
Chúng tôi cần một số pragmas ngôn ngữ và nhập khẩu:
{-# LANGUAGE TypeOperators, DefaultSignatures, DeriveGeneric, FlexibleContexts, FlexibleInstances #-}
module Example where
import GHC.Generics hiding(C, D)
Bây giờ chúng ta đưa ra một số "trường hợp chung chung". Các loại generic tất cả đều có một tham số phantom x
, mà làm cho dụ đứng đầu phức tạp hơn một chút:
-- "Insert" a normal value into a generic value
instance C c => C (K1 i c x) where
double (K1 c) = K1 (double c)
-- Ignore meta-information (constructor names, type names, field names)
instance C (f x) => C (M1 i c f x) where
double (M1 f) = M1 (double f)
-- Tuple-like instance
instance (C (f x), C (g x)) => C ((f :*: g) x) where
double (f :*: g) = double f :*: double g
Bây giờ chúng ta xác định lại đẳng cấp của chúng tôi C
để tận dụng lợi thế của GC
class C a where
-- | Double all numbers
double :: a -> a
-- specify the default implementation for double
default double :: (Generic a, C (Rep a())) => a -> a
double = to0 . double . from0
-- from, with a more specialised type, to avoid ambiguity
from0 :: Generic a => a -> Rep a()
from0 = from
-- to, with a more specialised type, to avoid ambiguity
to0 :: Generic a => Rep a() -> a
to0 = to
Bây giờ chúng ta có thể xác định một số các trường hợp rất dễ dàng:
data D a = D a a a deriving Generic
instance C a => C (D a)
data D2 m = D2 (m Int) (m Int) deriving Generic
instance C (D2 D)
Cập nhật câu trả lời của tôi để tránh lớp trợ giúp; xem http://article.gmane.org/gmane.comp.lang.haskell.cafe/97079 – reinerp