GHC Generics'i öğrenmeye çalışıyorum. Birkaç örneği inceledikten sonra, genel bir Functor
örneği oluşturmaya çalıştım (GHC'nin bunları benim için otomatik olarak türetebileceğini dikkate almayın). Ancak, Generics ile parametreli veri türleri ile nasıl çalışılacağımı bilmediğimi fark ettim, gördüğüm tüm örnekler *
türündeydi. Bu mümkün mü ve eğer evet ise, nasıl? (Ayrıca, SYB gibi diğer benzer çerçevelerle de ilgileniyorum.)GHC.Generics (veya diğer benzer çerçeveler) kullanarak genel Functor örnekleri nasıl oluşturulur?
9
A
cevap
8
GHC Generics kullanarak çok sayıda örnek işlevi aramak için en iyi yer generic-deriving
package'dur. Orada Functor
sınıfının genel bir tanımı var. Kopyalama Generics.Deriving.Functor
den (biraz basitleştirilmiş):
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
Eğer Generic1
yerine Generic
türetmek zorunda bir veri türü bu kullanın. Generic1
gösteriminin temel farkı, parametre konumlarını kodlayan Par1
veri türünü kullanmasıdır.
3
* -> *
türünde veri türleri için Generic1
sınıfı vardır. Onunla çalışmak çoğunlukla *
türündeki veri tipleriyle aynıdır, ayrıca parametre için Par1
da vardır. Örneğin, unfoldable package numaramda kullandım.
GHC, "Generic1" örneklerini otomatik olarak türetiyor mu? –
@ PetrPudlák Tam otomatik olarak değil. Ancak, "DeriveGeneric" dil uzantısıyla, "türetme Jenerik" inin yanı sıra "Generic1" türetme işlevini de kullanabilirsiniz (sonuncusu yalnızca en az bir parametreli veri türleri için çalışır; son parametre ise '' 'tür). – kosmikus
@kosmikus Teşekkürler. Ne yazık ki amacım için daha karmaşık türlerle çalışmak istiyorum, muhtemelen Template Haskell'i kullanmak zorundayım. –