2013-07-19 45 views

回答

8

使用GHC Generics查找大量示例函數的最佳位置是generic-deriving package。那裏有一個Functor類的通用定義。複製從Generics.Deriving.Functor(略簡體):

class GFunctor' f where 
    gmap' :: (a -> b) -> f a -> f b 

instance GFunctor' U1 where 
    gmap' _ U1 = U1 

instance GFunctor' Par1 where 
    gmap' f (Par1 a) = Par1 (f a) 

instance GFunctor' (K1 i c) where 
    gmap' _ (K1 a) = K1 a 

instance (GFunctor f) => GFunctor' (Rec1 f) where 
    gmap' f (Rec1 a) = Rec1 (gmap f a) 

instance (GFunctor' f) => GFunctor' (M1 i c f) where 
    gmap' f (M1 a) = M1 (gmap' f a) 

instance (GFunctor' f, GFunctor' g) => GFunctor' (f :+: g) where 
    gmap' f (L1 a) = L1 (gmap' f a) 
    gmap' f (R1 a) = R1 (gmap' f a) 

instance (GFunctor' f, GFunctor' g) => GFunctor' (f :*: g) where 
    gmap' f (a :*: b) = gmap' f a :*: gmap' f b 

instance (GFunctor f, GFunctor' g) => GFunctor' (f :.: g) where 
    gmap' f (Comp1 x) = Comp1 (gmap (gmap' f) x) 


class GFunctor f where 
    gmap :: (a -> b) -> f a -> f b 
    default gmap :: (Generic1 f, GFunctor' (Rep1 f)) 
       => (a -> b) -> f a -> f b 
    gmap = gmapdefault 

gmapdefault :: (Generic1 f, GFunctor' (Rep1 f)) 
      => (a -> b) -> f a -> f b 
gmapdefault f = to1 . gmap' f . from1 

要在數據類型利用這一點,你必須得到Generic1而非GenericGeneric1表示法的關鍵區別在於它使用編碼參數位置的Par1數據類型。

3

* -> *類型的數據類型有Generic1類。使用它的方式與*類型的數據類型大致相同,但參數的Par1也是如此。例如,我用它在我的unfoldable package中。

+0

GHC是否會自動導出'Generic1'的實例? –

+1

@PetrPudlák不完全自動。但是通過'DeriveGeneric'語言擴展,你可以使用'派生Generic'以及'派生Generic1'(後者只適用於至少有一個參數的數據類型,最後一個參數類型爲'*')。 – kosmikus

+0

@kosmikus謝謝。不幸的是,對於我的目標,我希望能夠處理更復雜的類型,所以我可能不得不使用Template Haskell。 –

相關問題