content: {-# LANGUAGE TypeOperators              #-}
  {-# LANGUAGE FlexibleContexts           #-}
  {-# LANGUAGE DefaultSignatures          #-}
  
  module GFunctor (
    -- * Generic Functor class
      GFunctor(..)
    ) where
  
  
  import GHC.Generics
  
  --------------------------------------------------------------------------------
  -- Generic fmap
  --------------------------------------------------------------------------------
  
  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 f = to1 . gmap' f . from1
  
  -- Base types instances
  instance GFunctor Maybe
  instance GFunctor []
  instance GFunctor ((,) a)
  