I'm trying to learn GHC Generics. After reviewing several examples, I wanted to try to create a generic Functor
instances (disregarding that GHC can derive them automatically for me). However, I realized I have no idea how to work with a parametrized data types with Generics, all the examples I've seen were of kind *
. Is this possible, and if yes, how? (I'm also interested in other similar frameworks, such as SYB.)
The best place to look for lots of example functions using GHC Generics is the generic-deriving
package. There's a generic definition of the Functor
class in there. Copying (slightly simplified) from 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
To use this on a datatype, you have to derive Generic1
rather than Generic
. The key difference of the Generic1
representation is that it makes use of the Par1
datatype that encodes parameter positions.
There is a Generic1
class for data types of kind * -> *
. Working with it is mostly the same as with data types of kind *
, except there's also Par1
for the parameter. I've used it in my unfoldable package for example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With