generic-functor 0.1.0.0 → 0.2.0.0
raw patch · 9 files changed
+1312/−872 lines, 9 filesdep +ap-normalizedep +transformersdep ~basesetup-changedPVP ok
version bump matches the API change (PVP)
Dependencies added: ap-normalize, transformers
Dependency ranges changed: base
API changes (from Hackage documentation)
- Generic.Functor: DeriveBifunctor :: f a b -> DeriveBifunctor f a b
- Generic.Functor: DeriveFunctor :: f a -> DeriveFunctor f a
- Generic.Functor: newtype DeriveBifunctor f a b
- Generic.Functor: newtype DeriveFunctor f a
- Generic.Functor.Internal: (:+) :: a -> b -> (:+) a b
- Generic.Functor.Internal: DeriveBifunctor :: f a b -> DeriveBifunctor f a b
- Generic.Functor.Internal: DeriveFunctor :: f a -> DeriveFunctor f a
- Generic.Functor.Internal: S :: arr -> arr' -> S arr arr'
- Generic.Functor.Internal: class GMap1 ((a -> b) :+ (c -> d) :+ ()) (Rep (f a c)) (Rep (f b d)) => GBifunctorRep a b c d f
- Generic.Functor.Internal: class Multimap_ arr x y
- Generic.Functor.Internal: data S arr arr'
- Generic.Functor.Internal: data a :+ b
- Generic.Functor.Internal: gmap1 :: GMap1 arr f g => arr -> f () -> g ()
- Generic.Functor.Internal: infixr 1 :+
- Generic.Functor.Internal: instance (Data.Bifunctor.Bifunctor f, Generic.Functor.Internal.Multimap arr x1 y1, Generic.Functor.Internal.Multimap arr x2 y2) => Generic.Functor.Internal.Multimap_ (Generic.Functor.Internal.S arr ()) (f x1 x2) (f y1 y2)
- Generic.Functor.Internal: instance (GHC.Base.Functor (f x), Generic.Functor.Internal.Multimap arr x2 y2) => Generic.Functor.Internal.Multimap_ (Generic.Functor.Internal.S arr ()) (f x x2) (f x y2)
- Generic.Functor.Internal: instance (GHC.Base.Functor f, Generic.Functor.Internal.Multimap arr x y) => Generic.Functor.Internal.Multimap_ (Generic.Functor.Internal.S arr ()) (f x) (f y)
- Generic.Functor.Internal: instance (Generic.Functor.Internal.GBifunctor f, Generic.Functor.Internal.GFirst f, Generic.Functor.Internal.GSecond f) => Data.Bifunctor.Bifunctor (Generic.Functor.Internal.DeriveBifunctor f)
- Generic.Functor.Internal: instance (Generic.Functor.Internal.GMap1 arr f1 g1, Generic.Functor.Internal.GMap1 arr f2 g2) => Generic.Functor.Internal.GMap1 arr (f1 GHC.Generics.:*: f2) (g1 GHC.Generics.:*: g2)
- Generic.Functor.Internal: instance (Generic.Functor.Internal.GMap1 arr f1 g1, Generic.Functor.Internal.GMap1 arr f2 g2) => Generic.Functor.Internal.GMap1 arr (f1 GHC.Generics.:+: f2) (g1 GHC.Generics.:+: g2)
- Generic.Functor.Internal: instance (Generic.Functor.Internal.Multimap arr y1 x1, Generic.Functor.Internal.Multimap arr x2 y2) => Generic.Functor.Internal.Multimap_ (Generic.Functor.Internal.S arr ()) (x1 -> x2) (y1 -> y2)
- Generic.Functor.Internal: instance (forall a c. GHC.Generics.Generic (f a c), forall a b c d. Generic.Functor.Internal.GBifunctorRep a b c d f) => Generic.Functor.Internal.GBifunctor f
- Generic.Functor.Internal: instance Generic.Functor.Internal.GFunctor f => GHC.Base.Functor (Generic.Functor.Internal.DeriveFunctor f)
- Generic.Functor.Internal: instance Generic.Functor.Internal.GMap1 ((a -> b) Generic.Functor.Internal.:+ ((c -> d) Generic.Functor.Internal.:+ ())) (GHC.Generics.Rep (f a c)) (GHC.Generics.Rep (f b d)) => Generic.Functor.Internal.GBifunctorRep a b c d f
- Generic.Functor.Internal: instance Generic.Functor.Internal.GMap1 ((a -> b) Generic.Functor.Internal.:+ ()) (GHC.Generics.Rep (f a c)) (GHC.Generics.Rep (f b c)) => Generic.Functor.Internal.GFirstRep a b c f
- Generic.Functor.Internal: instance Generic.Functor.Internal.GMap1 ((a -> b) Generic.Functor.Internal.:+ ()) (GHC.Generics.Rep (f a)) (GHC.Generics.Rep (f b)) => Generic.Functor.Internal.GFunctorRep a b f
- Generic.Functor.Internal: instance Generic.Functor.Internal.GMap1 ((a -> b) Generic.Functor.Internal.:+ ()) (GHC.Generics.Rep x) (GHC.Generics.Rep y) => Generic.Functor.Internal.GSolomap a b x y
- Generic.Functor.Internal: instance Generic.Functor.Internal.GMap1 arr (GHC.Generics.Rep x) (GHC.Generics.Rep y) => Generic.Functor.Internal.GMultimap arr x y
- Generic.Functor.Internal: instance Generic.Functor.Internal.GMap1 arr GHC.Generics.U1 GHC.Generics.U1
- Generic.Functor.Internal: instance Generic.Functor.Internal.GMap1 arr GHC.Generics.V1 GHC.Generics.V1
- Generic.Functor.Internal: instance Generic.Functor.Internal.GMap1 arr f g => Generic.Functor.Internal.GMap1 arr (GHC.Generics.M1 i c f) (GHC.Generics.M1 i' c'' g)
- Generic.Functor.Internal: instance Generic.Functor.Internal.Multimap ((a -> b) Generic.Functor.Internal.:+ ()) x y => Generic.Functor.Internal.Solomap a b x y
- Generic.Functor.Internal: instance Generic.Functor.Internal.Multimap arr x y => Generic.Functor.Internal.GMap1 arr (GHC.Generics.K1 i x) (GHC.Generics.K1 i' y)
- Generic.Functor.Internal: instance Generic.Functor.Internal.Multimap_ (Generic.Functor.Internal.S arr ((a -> b) Generic.Functor.Internal.:+ arr')) a b
- Generic.Functor.Internal: instance Generic.Functor.Internal.Multimap_ (Generic.Functor.Internal.S arr ()) (f x y) (f x y)
- Generic.Functor.Internal: instance Generic.Functor.Internal.Multimap_ (Generic.Functor.Internal.S arr ()) (f x) (f x)
- Generic.Functor.Internal: instance Generic.Functor.Internal.Multimap_ (Generic.Functor.Internal.S arr ()) x x
- Generic.Functor.Internal: instance Generic.Functor.Internal.Multimap_ (Generic.Functor.Internal.S arr arr') x y => Generic.Functor.Internal.Multimap_ (Generic.Functor.Internal.S arr ((a -> b) Generic.Functor.Internal.:+ arr')) x y
- Generic.Functor.Internal: instance Generic.Functor.Internal.Multimap_ (Generic.Functor.Internal.S2 arr) x y => Generic.Functor.Internal.Multimap arr x y
- Generic.Functor.Internal: multimap_ :: Multimap_ arr x y => arr -> x -> y
- Generic.Functor.Internal: newtype DeriveBifunctor f a b
- Generic.Functor.Internal: newtype DeriveFunctor f a
- Generic.Functor.Internal: s2 :: arr -> S2 arr
- Generic.Functor.Internal: type S2 arr = S arr arr
+ Generic.Functor: GenericBifunctor :: f a b -> GenericBifunctor f a b
+ Generic.Functor: GenericFunctor :: f a -> GenericFunctor f a
+ Generic.Functor: class (forall a b. Generic (t a b), forall a b c d. GBifoldMapRep a b c d m t) => GBifoldMap m t
+ Generic.Functor: class (forall m. Monoid m => GBifoldMap m t) => GBifoldable t
+ Generic.Functor: class (forall a c. Generic (f a c), forall a b c d. GBimapRep a b c d f) => GBimap f
+ Generic.Functor: class (forall f. Applicative f => GBitraverse f t) => GBitraversable t
+ Generic.Functor: class (forall a b. Generic (t a b), forall a b c d. GBitraverseRep a b c d f t) => GBitraverse f t
+ Generic.Functor: class (forall a. Generic (t a), forall a b. GFoldMapRep a b m t) => GFoldMap m t
+ Generic.Functor: class (forall m. Monoid m => GFoldMap m t) => GFoldable t
+ Generic.Functor: class (forall f. Applicative f => GBitraverse f t) => GTraversable t
+ Generic.Functor: class (forall a. Generic (t a), forall a b. GTraverseRep a b f t) => GTraverse f t
+ Generic.Functor: gbifoldMap :: forall t m a b. (GBifoldMap m t, Monoid m) => (a -> m) -> (b -> m) -> t a b -> m
+ Generic.Functor: gbitraverse :: forall t f a b c d. (GBitraverse f t, Applicative f) => (a -> f b) -> (c -> f d) -> t a c -> f (t b d)
+ Generic.Functor: gfoldMap :: forall t m a. (GFoldMap m t, Monoid m) => (a -> m) -> t a -> m
+ Generic.Functor: gtraverse :: forall t f a b. (GTraverse f t, Applicative f) => (a -> f b) -> t a -> f (t b)
+ Generic.Functor: newtype GenericBifunctor f a b
+ Generic.Functor: newtype GenericFunctor f a
+ Generic.Functor.Internal: GenericBifunctor :: f a b -> GenericBifunctor f a b
+ Generic.Functor.Internal: GenericFunctor :: f a -> GenericFunctor f a
+ Generic.Functor.Internal: class (forall a b. Generic (t a b), forall a b c d. GBifoldMapRep a b c d m t) => GBifoldMap m t
+ Generic.Functor.Internal: class GFoldMap1 m (Default Incoherent (Fold m a b :+ Fold m c d)) (Rep (t a c)) (Rep (t b d)) => GBifoldMapRep a b c d m t
+ Generic.Functor.Internal: class (forall m. Monoid m => GBifoldMap m t) => GBifoldable t
+ Generic.Functor.Internal: class (forall a c. Generic (f a c), forall a b c d. GBimapRep a b c d f) => GBimap f
+ Generic.Functor.Internal: class GMap1 (Default Incoherent ((a -> b) :+ (c -> d))) (Rep (f a c)) (Rep (f b d)) => GBimapRep a b c d f
+ Generic.Functor.Internal: class (forall f. Applicative f => GBitraverse f t) => GBitraversable t
+ Generic.Functor.Internal: class (forall a b. Generic (t a b), forall a b c d. GBitraverseRep a b c d f t) => GBitraverse f t
+ Generic.Functor.Internal: class GTraverse1 f (Default Incoherent ((a -> f b) :+ (c -> f d))) (Rep (t a c)) (Rep (t b d)) => GBitraverseRep a b c d f t
+ Generic.Functor.Internal: class (forall a. Generic (t a), forall a b. GFoldMapRep a b m t) => GFoldMap m t
+ Generic.Functor.Internal: class GMultimapK (Const (EndoM m)) arr f g => GFoldMap1 m arr f g
+ Generic.Functor.Internal: class GFoldMap1 m (Default Incoherent (Fold m a b)) (Rep (t a)) (Rep (t b)) => GFoldMapRep a b m t
+ Generic.Functor.Internal: class (forall m. Monoid m => GFoldMap m t) => GFoldable t
+ Generic.Functor.Internal: class GMultimapK m arr f g
+ Generic.Functor.Internal: class (forall f. Applicative f => GBitraverse f t) => GTraversable t
+ Generic.Functor.Internal: class (forall a. Generic (t a), forall a b. GTraverseRep a b f t) => GTraverse f t
+ Generic.Functor.Internal: class GMultimapK (Aps m) arr f g => GTraverse1 m arr f g
+ Generic.Functor.Internal: class GTraverse1 f (Default Incoherent (a -> f b)) (Rep (t a)) (Rep (t b)) => GTraverseRep a b f t
+ Generic.Functor.Internal: coerceBifoldMap :: Coercible t u => (am -> bm -> t -> m) -> am -> bm -> u -> m
+ Generic.Functor.Internal: coerceFoldMap :: Coercible t u => (am -> t -> m) -> am -> u -> m
+ Generic.Functor.Internal: foldToConst :: Monoid m => Fold m x y -> x -> Const (EndoM m) y
+ Generic.Functor.Internal: gbifoldMap :: forall t m a b. (GBifoldMap m t, Monoid m) => (a -> m) -> (b -> m) -> t a b -> m
+ Generic.Functor.Internal: gbitraverse :: forall t f a b c d. (GBitraverse f t, Applicative f) => (a -> f b) -> (c -> f d) -> t a c -> f (t b d)
+ Generic.Functor.Internal: gfoldMap :: forall t m a. (GFoldMap m t, Monoid m) => (a -> m) -> t a -> m
+ Generic.Functor.Internal: gfoldMapRep :: forall m arr f. (GFoldMap1 m arr f f, Monoid m) => arr -> f () -> m
+ Generic.Functor.Internal: gmapRep :: GMap1 arr f g => arr -> f () -> g ()
+ Generic.Functor.Internal: gmultimapK :: GMultimapK m arr f g => arr -> f () -> m (g ())
+ Generic.Functor.Internal: gtraverse :: forall t f a b. (GTraverse f t, Applicative f) => (a -> f b) -> t a -> f (t b)
+ Generic.Functor.Internal: gtraverseRep :: GTraverse1 m arr f g => arr -> f () -> Aps m (g ())
+ Generic.Functor.Internal: instance (Generic.Functor.Internal.GBimap f, Generic.Functor.Internal.GFirst f, Generic.Functor.Internal.GSecond f) => Generic.Functor.Internal.GBifunctor f
+ Generic.Functor.Internal: instance (Generic.Functor.Internal.GMultimapK m arr f g, GHC.Base.Functor m) => Generic.Functor.Internal.GMultimapK m arr (GHC.Generics.M1 i c f) (GHC.Generics.M1 i' c' g)
+ Generic.Functor.Internal: instance (Generic.Functor.Internal.GMultimapK m arr f1 g1, Generic.Functor.Internal.GMultimapK m arr f2 g2, GHC.Base.Applicative m) => Generic.Functor.Internal.GMultimapK m arr (f1 GHC.Generics.:*: f2) (g1 GHC.Generics.:*: g2)
+ Generic.Functor.Internal: instance (Generic.Functor.Internal.GMultimapK m arr f1 g1, Generic.Functor.Internal.GMultimapK m arr f2 g2, GHC.Base.Applicative m) => Generic.Functor.Internal.GMultimapK m arr (f1 GHC.Generics.:+: f2) (g1 GHC.Generics.:+: g2)
+ Generic.Functor.Internal: instance (Generic.Functor.Internal.Implicit.Multifold_ m arr x y, GHC.Base.Monoid m) => Generic.Functor.Internal.GMultimapK (Data.Functor.Const.Const (Generic.Functor.Internal.EndoM m)) arr (GHC.Generics.K1 i x) (GHC.Generics.K1 i' y)
+ Generic.Functor.Internal: instance (forall (f :: * -> *). GHC.Base.Applicative f => Generic.Functor.Internal.GBitraverse f t) => Generic.Functor.Internal.GBitraversable t
+ Generic.Functor.Internal: instance (forall (f :: * -> *). GHC.Base.Applicative f => Generic.Functor.Internal.GBitraverse f t) => Generic.Functor.Internal.GTraversable t
+ Generic.Functor.Internal: instance (forall a b. GHC.Generics.Generic (t a b), forall a b c d. Generic.Functor.Internal.GBifoldMapRep a b c d m t) => Generic.Functor.Internal.GBifoldMap m t
+ Generic.Functor.Internal: instance (forall a b. GHC.Generics.Generic (t a b), forall a b c d. Generic.Functor.Internal.GBitraverseRep a b c d f t) => Generic.Functor.Internal.GBitraverse f t
+ Generic.Functor.Internal: instance (forall a c. GHC.Generics.Generic (f a c), forall a b c d. Generic.Functor.Internal.GBimapRep a b c d f) => Generic.Functor.Internal.GBimap f
+ Generic.Functor.Internal: instance (forall a. GHC.Generics.Generic (t a), forall a b. Generic.Functor.Internal.GFoldMapRep a b m t) => Generic.Functor.Internal.GFoldMap m t
+ Generic.Functor.Internal: instance (forall a. GHC.Generics.Generic (t a), forall a b. Generic.Functor.Internal.GTraverseRep a b f t) => Generic.Functor.Internal.GTraverse f t
+ Generic.Functor.Internal: instance (forall m. GHC.Base.Monoid m => Generic.Functor.Internal.GBifoldMap m t) => Generic.Functor.Internal.GBifoldable t
+ Generic.Functor.Internal: instance (forall m. GHC.Base.Monoid m => Generic.Functor.Internal.GFoldMap m t) => Generic.Functor.Internal.GFoldable t
+ Generic.Functor.Internal: instance GHC.Base.Applicative m => Generic.Functor.Internal.GMultimapK m arr GHC.Generics.U1 GHC.Generics.U1
+ Generic.Functor.Internal: instance Generic.Functor.Internal.GBifoldable f => Data.Bifoldable.Bifoldable (Generic.Functor.Internal.GenericBifunctor f)
+ Generic.Functor.Internal: instance Generic.Functor.Internal.GBifunctor f => Data.Bifunctor.Bifunctor (Generic.Functor.Internal.GenericBifunctor f)
+ Generic.Functor.Internal: instance Generic.Functor.Internal.GFoldMap1 m (Generic.Functor.Internal.Implicit.Default Generic.Functor.Internal.Implicit.Incoherent (Generic.Functor.Internal.Implicit.Fold m a b Generic.Functor.Internal.Implicit.:+ Generic.Functor.Internal.Implicit.Fold m c d)) (GHC.Generics.Rep (t a c)) (GHC.Generics.Rep (t b d)) => Generic.Functor.Internal.GBifoldMapRep a b c d m t
+ Generic.Functor.Internal: instance Generic.Functor.Internal.GFoldMap1 m (Generic.Functor.Internal.Implicit.Default Generic.Functor.Internal.Implicit.Incoherent (Generic.Functor.Internal.Implicit.Fold m a b)) (GHC.Generics.Rep (t a)) (GHC.Generics.Rep (t b)) => Generic.Functor.Internal.GFoldMapRep a b m t
+ Generic.Functor.Internal: instance Generic.Functor.Internal.GFoldable f => Data.Foldable.Foldable (Generic.Functor.Internal.GenericFunctor f)
+ Generic.Functor.Internal: instance Generic.Functor.Internal.GFunctor f => GHC.Base.Functor (Generic.Functor.Internal.GenericFunctor f)
+ Generic.Functor.Internal: instance Generic.Functor.Internal.GMap1 (Generic.Functor.Internal.Implicit.Default Generic.Functor.Internal.Implicit.Incoherent ((a -> b) Generic.Functor.Internal.Implicit.:+ (c -> d))) (GHC.Generics.Rep (f a c)) (GHC.Generics.Rep (f b d)) => Generic.Functor.Internal.GBimapRep a b c d f
+ Generic.Functor.Internal: instance Generic.Functor.Internal.GMap1 (Generic.Functor.Internal.Implicit.Default Generic.Functor.Internal.Implicit.Incoherent (a -> b)) (GHC.Generics.Rep (f a c)) (GHC.Generics.Rep (f b c)) => Generic.Functor.Internal.GFirstRep a b c f
+ Generic.Functor.Internal: instance Generic.Functor.Internal.GMap1 (Generic.Functor.Internal.Implicit.Default Generic.Functor.Internal.Implicit.Incoherent (a -> b)) (GHC.Generics.Rep (f a)) (GHC.Generics.Rep (f b)) => Generic.Functor.Internal.GFunctorRep a b f
+ Generic.Functor.Internal: instance Generic.Functor.Internal.GMap1 (Generic.Functor.Internal.Implicit.Default Generic.Functor.Internal.Implicit.Incoherent arr) (GHC.Generics.Rep x) (GHC.Generics.Rep y) => Generic.Functor.Internal.GMultimap arr x y
+ Generic.Functor.Internal: instance Generic.Functor.Internal.GMultimap (a -> b) x y => Generic.Functor.Internal.GSolomap a b x y
+ Generic.Functor.Internal: instance Generic.Functor.Internal.GMultimapK (ApNormalize.Aps.Aps m) arr f g => Generic.Functor.Internal.GTraverse1 m arr f g
+ Generic.Functor.Internal: instance Generic.Functor.Internal.GMultimapK (Data.Functor.Const.Const (Generic.Functor.Internal.EndoM m)) arr (GHC.Generics.K1 i x) (GHC.Generics.K1 i x)
+ Generic.Functor.Internal: instance Generic.Functor.Internal.GMultimapK (Data.Functor.Const.Const (Generic.Functor.Internal.EndoM m)) arr f g => Generic.Functor.Internal.GFoldMap1 m arr f g
+ Generic.Functor.Internal: instance Generic.Functor.Internal.GMultimapK Data.Functor.Identity.Identity arr f g => Generic.Functor.Internal.GMap1 arr f g
+ Generic.Functor.Internal: instance Generic.Functor.Internal.GMultimapK m arr GHC.Generics.V1 GHC.Generics.V1
+ Generic.Functor.Internal: instance Generic.Functor.Internal.GTraverse1 f (Generic.Functor.Internal.Implicit.Default Generic.Functor.Internal.Implicit.Incoherent ((a -> f b) Generic.Functor.Internal.Implicit.:+ (c -> f d))) (GHC.Generics.Rep (t a c)) (GHC.Generics.Rep (t b d)) => Generic.Functor.Internal.GBitraverseRep a b c d f t
+ Generic.Functor.Internal: instance Generic.Functor.Internal.GTraverse1 f (Generic.Functor.Internal.Implicit.Default Generic.Functor.Internal.Implicit.Incoherent (a -> f b)) (GHC.Generics.Rep (t a)) (GHC.Generics.Rep (t b)) => Generic.Functor.Internal.GTraverseRep a b f t
+ Generic.Functor.Internal: instance Generic.Functor.Internal.Implicit.MultimapI (Generic.Functor.Internal.Implicit.Default Generic.Functor.Internal.Implicit.Incoherent arr) x y => Generic.Functor.Internal.Multimap arr x y
+ Generic.Functor.Internal: instance Generic.Functor.Internal.Implicit.MultimapI arr x y => Generic.Functor.Internal.GMultimapK Data.Functor.Identity.Identity arr (GHC.Generics.K1 i x) (GHC.Generics.K1 i' y)
+ Generic.Functor.Internal: instance Generic.Functor.Internal.Implicit.Multitraverse m arr x y => Generic.Functor.Internal.GMultimapK (ApNormalize.Aps.Aps m) arr (GHC.Generics.K1 i x) (GHC.Generics.K1 i' y)
+ Generic.Functor.Internal: instance Generic.Functor.Internal.Multimap (a -> b) x y => Generic.Functor.Internal.Solomap a b x y
+ Generic.Functor.Internal: liftEndoM :: Monoid m => m -> EndoM m
+ Generic.Functor.Internal: newtype GenericBifunctor f a b
+ Generic.Functor.Internal: newtype GenericFunctor f a
+ Generic.Functor.Internal: type EndoM m = Endo (Maybe m)
+ Generic.Functor.Internal: unEndoM :: Monoid m => EndoM m -> m
+ Generic.Functor.Internal.Implicit: (:+) :: a -> b -> (:+) a b
+ Generic.Functor.Internal.Implicit: AnyBifunctor :: AnyBifunctor
+ Generic.Functor.Internal.Implicit: AnyFunctor :: AnyFunctor
+ Generic.Functor.Internal.Implicit: AnyId :: AnyId
+ Generic.Functor.Internal.Implicit: Fold :: (x -> m) -> Fold m x y
+ Generic.Functor.Internal.Implicit: Incoherent :: Incoherent
+ Generic.Functor.Internal.Implicit: NilArr :: NilArr
+ Generic.Functor.Internal.Implicit: Rule :: rule -> mode -> Rule rule mode
+ Generic.Functor.Internal.Implicit: S :: arr -> arr' -> S arr arr'
+ Generic.Functor.Internal.Implicit: [unFold] :: Fold m x y -> x -> m
+ Generic.Functor.Internal.Implicit: catbimap :: BifunctorOf cat t => cat a b -> cat c d -> cat (t a c) (t b d)
+ Generic.Functor.Internal.Implicit: catid :: CatLike cat => cat x x
+ Generic.Functor.Internal.Implicit: catmap :: FunctorOf cat t => cat a b -> cat (t a) (t b)
+ Generic.Functor.Internal.Implicit: class BifunctorOf cat t
+ Generic.Functor.Internal.Implicit: class CatLike cat
+ Generic.Functor.Internal.Implicit: class Coercible warr arr => CoercibleKleisli (f :: Type -> Type) warr arr
+ Generic.Functor.Internal.Implicit: class FunctorOf cat t
+ Generic.Functor.Internal.Implicit: class MultimapOf (Fold m) arr x y => Multifold_ m arr x y
+ Generic.Functor.Internal.Implicit: class MultimapOf (->) arr x y => MultimapI arr x y
+ Generic.Functor.Internal.Implicit: class Multimap_ cat (S2 arr) x y => MultimapOf cat arr x y
+ Generic.Functor.Internal.Implicit: class Multimap_ cat arr x y
+ Generic.Functor.Internal.Implicit: class Multitraverse_ f arr x y => Multitraverse f arr x y
+ Generic.Functor.Internal.Implicit: data AnyBifunctor
+ Generic.Functor.Internal.Implicit: data AnyFunctor
+ Generic.Functor.Internal.Implicit: data AnyId
+ Generic.Functor.Internal.Implicit: data Incoherent
+ Generic.Functor.Internal.Implicit: data NilArr
+ Generic.Functor.Internal.Implicit: data Rule rule mode
+ Generic.Functor.Internal.Implicit: data S arr arr'
+ Generic.Functor.Internal.Implicit: data a :+ b
+ Generic.Functor.Internal.Implicit: def :: mode -> arr -> Default mode arr
+ Generic.Functor.Internal.Implicit: defaultIncoherent :: arr -> Default Incoherent arr
+ Generic.Functor.Internal.Implicit: infixr 1 :+
+ Generic.Functor.Internal.Implicit: instance (Data.Bifoldable.Bifoldable t, GHC.Base.Monoid m) => Generic.Functor.Internal.Implicit.BifunctorOf (Generic.Functor.Internal.Implicit.Fold m) t
+ Generic.Functor.Internal.Implicit: instance (Data.Foldable.Foldable t, GHC.Base.Monoid m) => Generic.Functor.Internal.Implicit.FunctorOf (Generic.Functor.Internal.Implicit.Fold m) t
+ Generic.Functor.Internal.Implicit: instance (GHC.Base.Applicative f, Data.Bitraversable.Bitraversable t) => Generic.Functor.Internal.Implicit.BifunctorOf (Control.Arrow.Kleisli f) t
+ Generic.Functor.Internal.Implicit: instance (GHC.Base.Applicative f, Data.Traversable.Traversable t) => Generic.Functor.Internal.Implicit.FunctorOf (Control.Arrow.Kleisli f) t
+ Generic.Functor.Internal.Implicit: instance (Generic.Functor.Internal.Implicit.BifunctorOf cat f, Generic.Functor.Internal.Implicit.MultimapOf cat arr x1 y1, Generic.Functor.Internal.Implicit.MultimapOf cat arr x2 y2) => Generic.Functor.Internal.Implicit.Multimap_ cat (Generic.Functor.Internal.Implicit.S arr (Generic.Functor.Internal.Implicit.Rule Generic.Functor.Internal.Implicit.AnyBifunctor Generic.Functor.Internal.Implicit.Incoherent Generic.Functor.Internal.Implicit.:+ arr')) (f x1 x2) (f y1 y2)
+ Generic.Functor.Internal.Implicit: instance (Generic.Functor.Internal.Implicit.CoercibleKleisli f a b, Generic.Functor.Internal.Implicit.CoercibleKleisli f arr arr') => Generic.Functor.Internal.Implicit.CoercibleKleisli f (a Generic.Functor.Internal.Implicit.:+ arr) (b Generic.Functor.Internal.Implicit.:+ arr')
+ Generic.Functor.Internal.Implicit: instance (Generic.Functor.Internal.Implicit.FunctorOf cat f, Generic.Functor.Internal.Implicit.MultimapOf cat arr x y) => Generic.Functor.Internal.Implicit.Multimap_ cat (Generic.Functor.Internal.Implicit.S arr (Generic.Functor.Internal.Implicit.Rule Generic.Functor.Internal.Implicit.AnyFunctor Generic.Functor.Internal.Implicit.Incoherent Generic.Functor.Internal.Implicit.:+ arr')) (f x) (f y)
+ Generic.Functor.Internal.Implicit: instance (Generic.Functor.Internal.Implicit.MultimapOf (->) arr y1 x1, Generic.Functor.Internal.Implicit.MultimapOf (->) arr x2 y2) => Generic.Functor.Internal.Implicit.Multimap_ (->) (Generic.Functor.Internal.Implicit.S arr (Generic.Functor.Internal.Implicit.Rule Generic.Functor.Internal.Implicit.AnyBifunctor Generic.Functor.Internal.Implicit.Incoherent Generic.Functor.Internal.Implicit.:+ arr')) (x1 -> x2) (y1 -> y2)
+ Generic.Functor.Internal.Implicit: instance (b2 GHC.Types.~ f c, a GHC.Types.~ Control.Arrow.Kleisli f b1 c) => Generic.Functor.Internal.Implicit.CoercibleKleisli f a (b1 -> b2)
+ Generic.Functor.Internal.Implicit: instance (d GHC.Types.~ Generic.Functor.Internal.Implicit.NilArr) => Generic.Functor.Internal.Implicit.CoercibleKleisli f d Generic.Functor.Internal.Implicit.NilArr
+ Generic.Functor.Internal.Implicit: instance (d GHC.Types.~ Generic.Functor.Internal.Implicit.Rule rule mode) => Generic.Functor.Internal.Implicit.CoercibleKleisli f d (Generic.Functor.Internal.Implicit.Rule rule mode)
+ Generic.Functor.Internal.Implicit: instance Data.Bifunctor.Bifunctor t => Generic.Functor.Internal.Implicit.BifunctorOf (->) t
+ Generic.Functor.Internal.Implicit: instance GHC.Base.Applicative f => Generic.Functor.Internal.Implicit.CatLike (Control.Arrow.Kleisli f)
+ Generic.Functor.Internal.Implicit: instance GHC.Base.Functor t => Generic.Functor.Internal.Implicit.FunctorOf (->) t
+ Generic.Functor.Internal.Implicit: instance GHC.Base.Monoid m => Generic.Functor.Internal.Implicit.CatLike (Generic.Functor.Internal.Implicit.Fold m)
+ Generic.Functor.Internal.Implicit: instance Generic.Functor.Internal.Implicit.CatLike (->)
+ Generic.Functor.Internal.Implicit: instance Generic.Functor.Internal.Implicit.CatLike cat => Generic.Functor.Internal.Implicit.Multimap_ cat (Generic.Functor.Internal.Implicit.S arr (Generic.Functor.Internal.Implicit.Rule Generic.Functor.Internal.Implicit.AnyId Generic.Functor.Internal.Implicit.Incoherent Generic.Functor.Internal.Implicit.:+ arr')) x x
+ Generic.Functor.Internal.Implicit: instance Generic.Functor.Internal.Implicit.MultimapOf (->) arr x y => Generic.Functor.Internal.Implicit.MultimapI arr x y
+ Generic.Functor.Internal.Implicit: instance Generic.Functor.Internal.Implicit.MultimapOf (Generic.Functor.Internal.Implicit.Fold m) arr x y => Generic.Functor.Internal.Implicit.Multifold_ m arr x y
+ Generic.Functor.Internal.Implicit: instance Generic.Functor.Internal.Implicit.Multimap_ cat (Generic.Functor.Internal.Implicit.S arr (arr0 Generic.Functor.Internal.Implicit.:+ (arr1 Generic.Functor.Internal.Implicit.:+ arr2))) x y => Generic.Functor.Internal.Implicit.Multimap_ cat (Generic.Functor.Internal.Implicit.S arr ((arr0 Generic.Functor.Internal.Implicit.:+ arr1) Generic.Functor.Internal.Implicit.:+ arr2)) x y
+ Generic.Functor.Internal.Implicit: instance Generic.Functor.Internal.Implicit.Multimap_ cat (Generic.Functor.Internal.Implicit.S arr (cat a b Generic.Functor.Internal.Implicit.:+ arr')) a b
+ Generic.Functor.Internal.Implicit: instance Generic.Functor.Internal.Implicit.Multimap_ cat (Generic.Functor.Internal.Implicit.S arr arr') x y => Generic.Functor.Internal.Implicit.Multimap_ cat (Generic.Functor.Internal.Implicit.S arr (() Generic.Functor.Internal.Implicit.:+ arr')) x y
+ Generic.Functor.Internal.Implicit: instance Generic.Functor.Internal.Implicit.Multimap_ cat (Generic.Functor.Internal.Implicit.S arr arr') x y => Generic.Functor.Internal.Implicit.Multimap_ cat (Generic.Functor.Internal.Implicit.S arr (Generic.Functor.Internal.Implicit.NilArr Generic.Functor.Internal.Implicit.:+ arr')) x y
+ Generic.Functor.Internal.Implicit: instance Generic.Functor.Internal.Implicit.Multimap_ cat (Generic.Functor.Internal.Implicit.S arr arr') x y => Generic.Functor.Internal.Implicit.Multimap_ cat (Generic.Functor.Internal.Implicit.S arr (arr0 Generic.Functor.Internal.Implicit.:+ arr')) x y
+ Generic.Functor.Internal.Implicit: instance Generic.Functor.Internal.Implicit.Multimap_ cat (Generic.Functor.Internal.Implicit.S2 arr) x y => Generic.Functor.Internal.Implicit.MultimapOf cat arr x y
+ Generic.Functor.Internal.Implicit: instance Generic.Functor.Internal.Implicit.Multitraverse_ f arr x y => Generic.Functor.Internal.Implicit.Multitraverse f arr x y
+ Generic.Functor.Internal.Implicit: multifold_ :: forall m arr x y. Multifold_ m arr x y => arr -> Fold m x y
+ Generic.Functor.Internal.Implicit: multimapI :: forall arr x y. MultimapI arr x y => arr -> x -> y
+ Generic.Functor.Internal.Implicit: multimapOf :: forall cat arr x y. MultimapOf cat arr x y => arr -> cat x y
+ Generic.Functor.Internal.Implicit: multimap_ :: Multimap_ cat arr x y => arr -> cat x y
+ Generic.Functor.Internal.Implicit: multitraverse :: forall f arr x y. Multitraverse f arr x y => arr -> x -> f y
+ Generic.Functor.Internal.Implicit: newtype Fold m x y
+ Generic.Functor.Internal.Implicit: s2 :: arr -> S2 arr
+ Generic.Functor.Internal.Implicit: type Default mode arr = arr :+ Rule AnyId mode :+ Rule AnyFunctor mode :+ Rule AnyBifunctor mode :+ NilArr
+ Generic.Functor.Internal.Implicit: type Multitraverse_ f arr x y = (MultimapOf (Kleisli f) (WrapKleisli f arr) x y, CoercibleKleisli f (WrapKleisli f arr) arr)
+ Generic.Functor.Internal.Implicit: type S2 arr = S arr arr
+ Generic.Functor.Internal.Implicit: type family WrapKleisli (f :: Type -> Type) (arr :: Type)
- Generic.Functor: class (forall a c. Generic (f a c), forall a b c d. GBifunctorRep a b c d f) => GBifunctor f
+ Generic.Functor: class (GBimap f, GFirst f, GSecond f) => GBifunctor f
- Generic.Functor: class GMap1 arr (Rep x) (Rep y) => GMultimap arr x y
+ Generic.Functor: class GMap1 (Default Incoherent arr) (Rep x) (Rep y) => GMultimap arr x y
- Generic.Functor: class GMap1 ((a -> b) :+ ()) (Rep x) (Rep y) => GSolomap a b x y
+ Generic.Functor: class GMultimap (a -> b) x y => GSolomap a b x y
- Generic.Functor: class Multimap_ (S2 arr) x y => Multimap arr x y
+ Generic.Functor: class MultimapI (Default Incoherent arr) x y => Multimap arr x y
- Generic.Functor: class Multimap ((a -> b) :+ ()) x y => Solomap a b x y
+ Generic.Functor: class Multimap (a -> b) x y => Solomap a b x y
- Generic.Functor: gbimap :: forall f a b c d. GBifunctor f => (a -> b) -> (c -> d) -> f a c -> f b d
+ Generic.Functor: gbimap :: forall f a b c d. GBimap f => (a -> b) -> (c -> d) -> f a c -> f b d
- Generic.Functor.Internal: class (forall a c. Generic (f a c), forall a b c d. GBifunctorRep a b c d f) => GBifunctor f
+ Generic.Functor.Internal: class (GBimap f, GFirst f, GSecond f) => GBifunctor f
- Generic.Functor.Internal: class GMap1 ((a -> b) :+ ()) (Rep (f a c)) (Rep (f b c)) => GFirstRep a b c f
+ Generic.Functor.Internal: class GMap1 (Default Incoherent (a -> b)) (Rep (f a c)) (Rep (f b c)) => GFirstRep a b c f
- Generic.Functor.Internal: class GMap1 ((a -> b) :+ ()) (Rep (f a)) (Rep (f b)) => GFunctorRep a b f
+ Generic.Functor.Internal: class GMap1 (Default Incoherent (a -> b)) (Rep (f a)) (Rep (f b)) => GFunctorRep a b f
- Generic.Functor.Internal: class GMap1 arr f g
+ Generic.Functor.Internal: class GMultimapK Identity arr f g => GMap1 arr f g
- Generic.Functor.Internal: class GMap1 arr (Rep x) (Rep y) => GMultimap arr x y
+ Generic.Functor.Internal: class GMap1 (Default Incoherent arr) (Rep x) (Rep y) => GMultimap arr x y
- Generic.Functor.Internal: class GMap1 ((a -> b) :+ ()) (Rep x) (Rep y) => GSolomap a b x y
+ Generic.Functor.Internal: class GMultimap (a -> b) x y => GSolomap a b x y
- Generic.Functor.Internal: class Multimap_ (S2 arr) x y => Multimap arr x y
+ Generic.Functor.Internal: class MultimapI (Default Incoherent arr) x y => Multimap arr x y
- Generic.Functor.Internal: class Multimap ((a -> b) :+ ()) x y => Solomap a b x y
+ Generic.Functor.Internal: class Multimap (a -> b) x y => Solomap a b x y
- Generic.Functor.Internal: gbimap :: forall f a b c d. GBifunctor f => (a -> b) -> (c -> d) -> f a c -> f b d
+ Generic.Functor.Internal: gbimap :: forall f a b c d. GBimap f => (a -> b) -> (c -> d) -> f a c -> f b d
Files
- CHANGELOG.md +19/−12
- LICENSE +19/−19
- README.md +209/−202
- Setup.hs +2/−2
- generic-functor.cabal +44/−40
- src/Generic/Functor.hs +63/−38
- src/Generic/Functor/Internal.hs +511/−420
- src/Generic/Functor/Internal/Implicit.hs +225/−0
- test/test.hs +220/−139
CHANGELOG.md view
@@ -1,12 +1,19 @@-## 0.1.0.0--- Add `gmultimap`, `multimap`, `(:+)`-- Add `DeriveBifunctor`, `gbimap`, `gfirst`, `gsecond`--## 0.0.1.1--* Include README--## 0.0.1.0--* Create generic-functor+## 0.2.0.0 + +- Add `gfoldMap`, `gtraverse`, `gbifoldMap`, `gbitraverse` `GFoldable`, `GFoldMap`, `GTraversable`, `GTraverse`, `GBiFoldable`, `GBifoldMap`, `GBitraversable`, `GBitraverse` +- Rename `GBifunctor` to `GBimap`, and add new `GBifunctor` (class synonym for `GBimap`, `GFirst`, and `GSecond`) +- Rename `DeriveFunctor` to `GenericFunctor`, and rename `DeriveBifunctor` to `GenericBifunctor` +- Add instances for deriving-via `Foldable` and `Bifoldable` + +## 0.1.0.0 + +- Add `gmultimap`, `multimap`, `(:+)` +- Add `DeriveBifunctor`, `gbimap`, `gfirst`, `gsecond` + +## 0.0.1.1 + +* Include README + +## 0.0.1.0 + +* Create generic-functor
LICENSE view
@@ -1,19 +1,19 @@-Copyright Li-yao Xia (c) 2020--Permission is hereby granted, free of charge, to any person obtaining a copy of-this software and associated documentation files (the “Software”), to deal in-the Software without restriction, including without limitation the rights to-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies-of the Software, and to permit persons to whom the Software is furnished to do-so, subject to the following conditions:--The above copyright notice and this permission notice shall be included in all-copies or substantial portions of the Software.--THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE-SOFTWARE.+Copyright Li-yao Xia (c) 2020 + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the “Software”), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.
README.md view
@@ -1,202 +1,209 @@-# Generic functors [](https://hackage.haskell.org/package/generic-functor) [](https://gitlab.com/lysxia/generic-functor/-/commits/main)---Implementation of `Functor` instances and other functor-like structures-using `GHC.Generics`.--## Functors not over the last type parameter--The standard `Functor` class only applies to types that are functors over their-last type parameter. For example, in `Either e r`, `fmap` maps only `r`.--Using this library, `fmap`-like functions can be derived over any type-parameter of a `Generic` data type, all from the same definition `gsolomap`.--```haskell-{-# LANGUAGE DeriveGeneric #-}--import GHC.Generics (Generic)-import Generic.Functor (gsolomap)--data Result a r = Error a | Ok r -- Another name for Either- deriving Generic--mapError :: (a -> b) -> Result a r -> Result b r-mapError = gsolomap---- This one is fmap-mapOk :: (a -> b) -> Result e a -> Result e b-mapOk = gsolomap--mapBoth :: (a -> b) -> Result a a -> Result b b-mapBoth = gsolomap-```--`gsolomap` is **unsafe**. Misuse will break your program.-Read on for specifics.--### Usage--`gsolomap` should only be used to define **polymorphic** "`fmap`-like functions"-for `Generic` types.--The signature of `gsolomap` is:--```haskell-gsolomap :: (Generic x, Generic y, GSolomap a b x y) => (a -> b) -> (x -> y)-```--The types `x` and `y` must be specializations of the same user-defined `data`-type which is an instance of `Generic`, with some type parameters equal to `a`-or `b` respectively. At use sites of `gsolomap`, `a` and `b` must also be two-distinct universally quantified type variables, with no equality constraint-relating them with each other or any other type.--The guarantee is that `gsolomap` satisfies `gsolomap id = id`. Under the-condition that `a` and `b` are abstract, that equation uniquely determines the-implementation. (That uniqueness claim may be broken with GADTs and other-explicit uses of type equality constraints.)--In particular, `gsolomap` *must not* be specialized with types `a` and `b` that-are equal. A function defined using `gsolomap` is safe to specialize once-the `GSolomap` constraint has been discharged.--For instance the three functions above, `mapError`, `mapOk`, `mapBoth` are-sufficiently polymorphic.-They are each uniquely determined by their types and the equation `mapX id = id`.-(Without that equation, `mapBoth` has four implementations of the same type.)--## Compositions of functors--How many `fmap` do you need to map a function `a -> b` over-`(t, Maybe [Either Bool a])`?--You only need one `solomap`:--```haskell-type F t a = (t, Maybe [Either Bool a])--maps :: (a -> b) -> F t a -> F t b-maps = solomap-```--`solomap` can also see through bifunctors and there may be more than-one occurrence of the type parameter `a`.--```haskell-type F a = ([a], Either a ())--maps2 :: (a -> b) -> F a -> F b-maps2 = solomap-```--`solomap` is **unsafe**, subject to the same restrictions as `gsolomap`:-where `solomap` is used, the type of its first argument `(a -> b)` must refer-to two distinct universally quantified variables `a` and `b`.-Functions are safe to specialize only once the `Solomap` constraint is out of-their contexts.--```haskell-solomap :: Solomap a b x y => (a -> b) -> (x -> y)-```--## Functors of multiple parameters--You can also map with more than one function simultaneously.-For example with `a -> b` and `c -> d` over `(Maybe a, [(c, a)])`:--```haskell-type F a c = (Maybe a, [(c, a)])--bimaps :: (a -> b) -> (c -> d) -> F a c -> F b d-bimaps f g = multimap (f :+ g :+ ())-```--`multimap` takes a list of functions separated by `(:+)` and terminated by `()`.--There is also a `gmultimap`, generalizing `gsolomap`.--`gmultimap` and `multimap` are **unsafe**, similarly to `gsolomap` and `solomap`.--## Deriving `Functor`--This library enables `DerivingVia` for the `Functor` class.--```haskell-{-# LANGUAGE DeriveGeneric, DerivingVia #-}--import GHC.Generics (Generic)-import Generic.Functor (DeriveFunctor(..))--data Twice a = Twice (Either a a)- deriving Generic- deriving Functor via (DeriveFunctor Twice)-```--Note that there is already built-in support for deriving `Functor` in GHC with the-`DeriveFunctor` extension instead. If that extension ever chokes on a type, this-library might have a chance at handling it. (Open an issue if it does not!)--The `Twice` example just above is not handled by the `DeriveFunctor` extension:--```haskell-{-# LANGUAGE DeriveFunctor #-}--data Twice a = Twice (Either a a) deriving Functor--{-- error:- • Can't make a derived instance of ‘Functor Twice’:- Constructor ‘Twice’ must use the type variable only as the last argument of a data type--}-```--The [*generic-data*][generic-data] library also includes a generic implementation of `Functor`,-but only for instances of `Generic1`, which applies to much more restricted shapes-of `data` than `Generic`.--## Deriving `Bifunctor`--Similarly, we can use `DerivingVia` for the `Bifunctor` class-(from *base*, module `Data.Bifunctor`).--```haskell-{-# LANGUAGE DeriveGeneric, DerivingVia #-}--import GHC.Generics (Generic)-import Generic.Functor (DeriveFunctor(..), DeriveBifunctor(..))--data Tree a b = Node a (Tree a b) (Tree a b) | Leaf b- deriving Generic- deriving Functor via (DeriveFunctor (Tree a))- deriving Bifunctor via (DeriveBifunctor Tree)-```-------## Internal module policy--The public API is `Generic.Functor`. Don't use `Generic.Functor.Internal`.--## Future work--- Bifunctors and variants with more than one function argument.-- Functors in arbitrary categories.--## Related links--- [*generic-data*][generic-data]: utilities for `GHC.Generics` and deriving for- other standard classes.--- [*generic-lens*][generic-lens]: the `params` traversal uses a very similar implementation.--- [*one-liner*][one-liner]. [*product-profunctors*][pp]--- [*Deriving Bifunctors with Generics*](https://kcsongor.github.io/generic-deriving-bifunctor/),- blogpost by Csongor Kiss,- describing the main idea for the implementation (using incoherent instances).--[generic-data]: https://hackage.haskell.org/package/generic-data-[generic-lens]: https://hackage.haskell.org/package/generic-lens-[one-liner]: https://hackage.haskell.org/package/one-liner-[pp]: https://hackage.haskell.org/package/product-profunctors+# Generic functors [](https://hackage.haskell.org/package/generic-functor) [](https://gitlab.com/lysxia/generic-functor/-/commits/main) + + +Implementation of `Functor` instances and other functor-like structures +using `GHC.Generics`. + +## Functors not over the last type parameter + +The standard `Functor` class only applies to types that are functors over their +last type parameter. For example, in `Either e r`, `fmap` maps only `r`. + +Using this library, `fmap`-like functions can be derived over any type +parameter of a `Generic` data type, all from the same definition `gsolomap`. + +```haskell +{-# LANGUAGE DeriveGeneric #-} + +import GHC.Generics (Generic) +import Generic.Functor (gsolomap) + +data Result a r = Error a | Ok r -- Another name for Either + deriving Generic + +mapError :: (a -> b) -> Result a r -> Result b r +mapError = gsolomap + +-- This one is fmap +mapOk :: (a -> b) -> Result e a -> Result e b +mapOk = gsolomap + +mapBoth :: (a -> b) -> Result a a -> Result b b +mapBoth = gsolomap +``` + +`gsolomap` is **unsafe**. Misuse will break your program. +Read on for specifics. + +### Usage + +`gsolomap` should only be used to define **polymorphic** "`fmap`-like functions" +for `Generic` types. + +The signature of `gsolomap` is: + +```haskell +gsolomap :: (Generic x, Generic y, GSolomap a b x y) => (a -> b) -> (x -> y) +``` + +The types `x` and `y` must be specializations of the same user-defined `data` +type which is an instance of `Generic`, with some type parameters equal to `a` +or `b` respectively. At use sites of `gsolomap`, `a` and `b` must also be two +distinct universally quantified type variables, with no equality constraint +relating them with each other or any other type. + +The guarantee is that `gsolomap` satisfies `gsolomap id = id`. Under the +condition that `a` and `b` are abstract, that equation uniquely determines the +implementation. (That uniqueness claim may be broken with GADTs and other +explicit uses of type equality constraints.) + +In particular, `gsolomap` *must not* be specialized with types `a` and `b` that +are equal. A function defined using `gsolomap` is safe to specialize once +the `GSolomap` constraint has been discharged. + +For instance the three functions above, `mapError`, `mapOk`, `mapBoth` are +sufficiently polymorphic. +They are each uniquely determined by their types and the equation `mapX id = id`. +(Without that equation, `mapBoth` has four implementations of the same type.) + +## Compositions of functors + +How many `fmap` do you need to map a function `a -> b` over +`(t, Maybe [Either Bool a])`? + +You only need one `solomap`: + +```haskell +type F t a = (t, Maybe [Either Bool a]) + +maps :: (a -> b) -> F t a -> F t b +maps = solomap +``` + +`solomap` can also see through bifunctors and there may be more than +one occurrence of the type parameter `a`. + +```haskell +type F a = ([a], Either a ()) + +maps2 :: (a -> b) -> F a -> F b +maps2 = solomap +``` + +`solomap` is **unsafe**, subject to the same restrictions as `gsolomap`: +where `solomap` is used, the type of its first argument `(a -> b)` must refer +to two distinct universally quantified variables `a` and `b`. +Functions are safe to specialize only once the `Solomap` constraint is out of +their contexts. + +```haskell +solomap :: Solomap a b x y => (a -> b) -> (x -> y) +``` + +## Functors of multiple parameters + +You can also map with more than one function simultaneously. +For example with `a -> b` and `c -> d` over `(Maybe a, [(c, a)])`: + +```haskell +type F a c = (Maybe a, [(c, a)]) + +bimaps :: (a -> b) -> (c -> d) -> F a c -> F b d +bimaps f g = multimap (f :+ g :+ ()) +``` + +`multimap` takes a list of functions separated by `(:+)` and terminated by `()`. + +There is also a `gmultimap`, generalizing `gsolomap`. + +`gmultimap` and `multimap` are **unsafe**, similarly to `gsolomap` and `solomap`. + +## Deriving `Functor` + +This library enables `DerivingVia` for the `Functor` class. + +```haskell +{-# LANGUAGE DeriveGeneric, DerivingVia #-} + +import GHC.Generics (Generic) +import Generic.Functor (GenericFunctor(..)) + +data Twice a = Twice (Either a a) + deriving Generic + deriving Functor via (GenericFunctor Twice) +``` + +Note that there is already built-in support for deriving `Functor` in GHC with the +`DeriveFunctor` extension instead. If that extension ever chokes on a type, this +library might have a chance at handling it. (Open an issue if it does not!) + +The `Twice` example just above is not handled by the `DeriveFunctor` extension: + +```haskell +{-# LANGUAGE DeriveFunctor #-} + +data Twice a = Twice (Either a a) deriving Functor + +{- + error: + • Can't make a derived instance of ‘Functor Twice’: + Constructor ‘Twice’ must use the type variable only as the last argument of a data type +-} +``` + +The [*generic-data*][generic-data] library also includes a generic implementation of `Functor`, +but only for instances of `Generic1`, which applies to much more restricted shapes +of `data` than `Generic`. + +## Deriving `Bifunctor` + +Similarly, we can use `DerivingVia` for the `Bifunctor` class +(from *base*, module `Data.Bifunctor`). + +```haskell +{-# LANGUAGE DeriveGeneric, DerivingVia #-} + +import GHC.Generics (Generic) +import Generic.Functor (GenericFunctor(..), GenericBifunctor(..)) + +data Tree a b = Node a (Tree a b) (Tree a b) | Leaf b + deriving Generic + deriving Functor via (GenericFunctor (Tree a)) + deriving Bifunctor via (GenericBifunctor Tree) +``` + +In summary, the newtype `GenericFunctor` can be used for `DerivingVia` +of the classes `Functor` and `Foldable`, and the newtype `GenericBifunctor` +for the classes `Bifunctor` and `Bifoldable`. + +Default implementations for the above classes are also available as standalone +functions (`gfmap`, `gfoldMap`, `gbimap`, `gbifoldMap`) and also for +`Traversable` and `Bitraversable` (`gtraverse`, `gbitraverse`). + +--- + +## Internal module policy + +The public API is `Generic.Functor`. Don't use `Generic.Functor.Internal`. + +## Future work + +- Functors in arbitrary categories. + +## Related links + +- [*generic-data*][generic-data]: utilities for `GHC.Generics` and deriving for + other standard classes. + +- [*generic-lens*][generic-lens]: the `params` traversal uses a very similar implementation. + +- [*one-liner*][one-liner]. [*product-profunctors*][pp] + +- [*Deriving Bifunctors with Generics*](https://kcsongor.github.io/generic-deriving-bifunctor/), + blogpost by Csongor Kiss, + describing the main idea for the implementation (using incoherent instances). + +[generic-data]: https://hackage.haskell.org/package/generic-data +[generic-lens]: https://hackage.haskell.org/package/generic-lens +[one-liner]: https://hackage.haskell.org/package/one-liner +[pp]: https://hackage.haskell.org/package/product-profunctors
Setup.hs view
@@ -1,2 +1,2 @@-import Distribution.Simple-main = defaultMain+import Distribution.Simple +main = defaultMain
generic-functor.cabal view
@@ -1,40 +1,44 @@-cabal-version: >=1.10-name: generic-functor-version: 0.1.0.0-synopsis: Deriving generalized functors with GHC.Generics-description:- Derive @fmap@, and other @fmap@-like functions where the- parameter of the functor could occur anywhere.- .- See the README for details.-homepage: https://gitlab.com/lysxia/generic-functor-bug-reports: https://gitlab.com/lysxia/generic-functor/-/issues-license: MIT-license-file: LICENSE-author: Li-yao Xia-maintainer: lysxia@gmail.com-copyright: Li-yao Xia 2020-category: Generics-build-type: Simple-extra-source-files: CHANGELOG.md, README.md--library- hs-source-dirs: src- exposed-modules:- Generic.Functor- Generic.Functor.Internal- build-depends: base >=4.12 && <4.15- default-language: Haskell2010--test-suite examples- hs-source-dirs: test- main-is: test.hs- build-depends:- generic-functor,- base- type: exitcode-stdio-1.0- default-language: Haskell2010--source-repository head- type: git- location: https://gitlab.com/lysxia/generic-functor+cabal-version: >=1.10 +name: generic-functor +version: 0.2.0.0 +synopsis: Deriving generalized functors with GHC.Generics +description: + Derive @fmap@, and other @fmap@-like functions where the + parameter of the functor could occur anywhere. + . + See the README for details. +homepage: https://gitlab.com/lysxia/generic-functor +bug-reports: https://gitlab.com/lysxia/generic-functor/-/issues +license: MIT +license-file: LICENSE +author: Li-yao Xia +maintainer: lysxia@gmail.com +copyright: Li-yao Xia 2020 +category: Generics +build-type: Simple +extra-source-files: CHANGELOG.md, README.md + +library + hs-source-dirs: src + exposed-modules: + Generic.Functor + Generic.Functor.Internal + Generic.Functor.Internal.Implicit + build-depends: + ap-normalize, + base >=4.12 && <4.15 + default-language: Haskell2010 + +test-suite examples + hs-source-dirs: test + main-is: test.hs + build-depends: + generic-functor, + transformers, + base + type: exitcode-stdio-1.0 + default-language: Haskell2010 + +source-repository head + type: git + location: https://gitlab.com/lysxia/generic-functor
src/Generic/Functor.hs view
@@ -1,38 +1,63 @@--- | Generic and generalized functors.--module Generic.Functor- ( -- * Derive functors-- -- ** Unary functors- gsolomap- , solomap-- -- ** N-ary functors- , gmultimap- , multimap- , (:+)(..)-- -- ** Derive Functor and Bifunctor-- -- *** DerivingVia- , DeriveFunctor(..)- , DeriveBifunctor(..)-- -- *** Generic method definitions- , gfmap- , gbimap- , gfirst- , gsecond-- -- * Auxiliary classes- , GFunctor()- , GBifunctor()- , GFirst()- , GSecond()- , GSolomap()- , Solomap()- , GMultimap()- , Multimap()- ) where--import Generic.Functor.Internal+-- | Generic and generalized functors. + +module Generic.Functor + ( -- * Derive functors + + -- ** Unary functors + gsolomap + , solomap + + -- ** N-ary functors + , gmultimap + , multimap + , (:+)(..) + + -- ** Derive Functor, Bifunctor, Foldable, Traversable + + -- *** DerivingVia + -- | The type synonyms 'GenericFunctor' and 'GenericBifunctor' can be + -- used with the @DerivingVia@ extension to derive 'Functor', 'Bifunctor', and 'Foldable'. + -- Sadly, 'Traversable' cannot be derived-via. + , GenericFunctor(..) + , GenericBifunctor(..) + + -- *** Generic method definitions + , gfmap + , gfoldMap + , gtraverse + + -- **** Bifunctors + , gbimap + , gfirst + , gsecond + , gbifoldMap + , gbitraverse + + -- * Auxiliary classes + + -- ** Related to standard classes + , GFunctor() + , GFoldable() + , GFoldMap() + , GTraversable() + , GTraverse() + + -- *** Bifunctors + , GBifunctor() + , GBimap() + , GFirst() + , GSecond() + , GBifoldable() + , GBifoldMap() + , GBitraversable() + , GBitraverse() + + -- ** Generalized functors + , GSolomap() + , Solomap() + , GMultimap() + , Multimap() + ) where + +import Generic.Functor.Internal +import Generic.Functor.Internal.Implicit
src/Generic/Functor/Internal.hs view
@@ -1,420 +1,511 @@-{-# LANGUAGE- AllowAmbiguousTypes,- ConstraintKinds,- EmptyCase,- FlexibleContexts,- FlexibleInstances,- MultiParamTypeClasses,- QuantifiedConstraints,- RankNTypes,- ScopedTypeVariables,- TypeApplications,- TypeOperators,- UndecidableInstances #-}--{-# OPTIONS_GHC -Wno-simplifiable-class-constraints #-}---- | This is an internal module. Look, don't touch.------ "Generic.Functor" is the public API.--module Generic.Functor.Internal where--import Data.Bifunctor-import Data.Coerce-import GHC.Generics hiding (S)---- | Generic implementation of 'fmap'. See also 'DeriveFunctor' for @DerivingVia@,--- using 'gfmap' under the hood.------ === Example------ @--- {-\# LANGUAGE DeriveGeneric \#-}------ import "GHC.Generics" ('Generic')--- import "Generic.Functor" ('gfmap')------ data Twice a = Twice (Either a a)--- deriving 'Generic'------ instance 'Functor' Twice where--- 'fmap' = 'gfmap'--- @------ Unlike 'gsolomap', 'gfmap' is safe to use in all contexts.-gfmap :: forall f a b. GFunctor f => (a -> b) -> (f a -> f b)-gfmap f = with @(GFunctorRep a b f) (to . gmap1 (f :+ ()) . from)---- | Generalized generic functor.------ 'gsolomap' is a generalization of 'gfmap' (generic 'fmap'),--- where the type parameter to be \"mapped\" does not have to be the last one.------ 'gsolomap' is __unsafe__: misuse will break your programs.--- Read the <#gsolomapusage Usage> section below for details.------ === Example------ @--- {-\# LANGUAGE DeriveGeneric \#-}------ import "GHC.Generics" ('Generic')--- import "Generic.Functor" ('gsolomap')------ data Result a r = Error a | Ok r -- Another name for Either--- deriving 'Generic'------ mapError :: (a -> b) -> Result a r -> Result b r--- mapError = 'gsolomap'------ mapOk :: (r -> s) -> Result a r -> Result a s--- mapOk = 'gsolomap'------ mapBoth :: (a -> b) -> Result a a -> Result b b--- mapBoth = 'gsolomap'--- @------ === Usage #gsolomapusage#------ (This also applies to 'solomap', 'gmultimap', and 'multimap'.)------ 'gsolomap' should only be used to define __polymorphic__ "@fmap@-like functions".--- It works only in contexts where @a@ and @b@ are two distinct, non-unifiable--- type variables. This is usually the case when they are bound by universal--- quantification (@forall a b. ...@), with no equality constraints on @a@ and--- @b@.------ The one guarantee of 'gsolomap' is that @'gsolomap' 'id' = 'id'@.--- Under the above conditions, that law and the types should uniquely determine--- the implementation, which 'gsolomap' seeks automatically.------ The unsafety is due to the use of incoherent instances as part of the--- definition of 'GSolomap'. Functions are safe to specialize after 'GSolomap'--- (and 'Solomap') constraints have been discharged.-gsolomap :: forall a b x y. (Generic x, Generic y, GSolomap a b x y) => (a -> b) -> (x -> y)-gsolomap f = to . gmap1 (f :+ ()) . from---- | Generalized implicit functor.------ Use this when @x@ and @y@ are applications of existing functors--- ('Functor', 'Bifunctor').------ This is a different use case from 'gfmap' and 'gsolomap', which make--- functors out of freshly declared @data@ types.------ 'solomap' is __unsafe__: misuse will break your programs.------ See the <#gsolomapusage Usage> section of 'gsolomap' for details.------ === Example------ @--- map1 :: (a -> b) -> Either e (Maybe [IO a]) -> Either e (Maybe [IO b])--- map1 = 'solomap'--- -- equivalent to: fmap . fmap . fmap . fmap------ map2 :: (a -> b) -> (e -> Either [a] r) -> (e -> Either [b] r)--- map2 = 'solomap'--- -- equivalent to: \\f -> fmap (bimap (fmap f) id)--- @-solomap :: forall a b x y. Solomap a b x y => (a -> b) -> (x -> y)-solomap f = multimap (f :+ ())---- | Generic n-ary functor.------ A generalization of 'gsolomap' to map over multiple parameters simultaneously.--- 'gmultimap' takes a list of functions separated by @(':+')@ and terminated by @()@.------ 'gmultimap' is __unsafe__: misuse will break your programs.--- The type of every function in the list must be some @(a -> b)@--- where @a@ and @b@ are distinct type variables.------ See the <#gsolomapusage Usage> section of 'gsolomap' for details.------ === Example------ @--- {-\# LANGUAGE DeriveGeneric \#-}------ import "GHC.Generics" ('Generic')--- import "Generic.Functor" ('gmultimap')------ data Three a b c = One a | Two b | Three c--- deriving 'Generic'------ mapThree :: (a -> a') -> (b -> b') -> (c -> c') -> Three a b c -> Three a' b' c'--- mapThree f g h = 'gmultimap' (f ':+' g ':+' h ':+' ())--- @-gmultimap :: forall arr x y. (Generic x, Generic y, GMultimap arr x y) => arr -> (x -> y)-gmultimap f = to . gmap1 f . from---- | Implicit n-ary functor.------ A generalization of 'solomap' to map over multiple parameters simultaneously.--- 'multimap' takes a list of functions separated by @(':+')@ and terminated by @()@.------ 'multimap' is __unsafe__: misuse will break your programs.--- The type of every function in the list must be some @(a -> b)@--- where @a@ and @b@ are distinct type variables.------ See the <#gsolomapusage Usage> section of 'gsolomap' for details.------ === Example------ @--- type F a b c = Either a (b, c)------ map3 :: (a -> a') -> (b -> b') -> (c -> c') -> F a b c -> F a' b' c'--- map3 f g h = 'multimap' (f ':+' g ':+' h ':+' ())--- -- equivalent to: \\f g h -> bimap f (bimap g h)--- @-multimap :: forall arr x y. Multimap arr x y => arr -> (x -> y)-multimap f = multimap_ (s2 f)---- | Generic implementation of 'bimap'. See also 'DeriveBifunctor'.-gbimap :: forall f a b c d. GBifunctor f => (a -> b) -> (c -> d) -> f a c -> f b d-gbimap f g = with @(GBifunctorRep a b c d f) (to . gmap1 (f :+ g :+ ()) . from)---- | Generic implementation of 'first'. See also 'DeriveBifunctor'.-gfirst :: forall f a b c. GFirst f => (a -> b) -> f a c -> f b c-gfirst f = with @(GFirstRep a b c f) (to . gmap1 (f :+ ()) . from)---- | Generic implementation of 'second'. See also 'DeriveBifunctor'.-gsecond :: forall f a c d. GSecond f => (c -> d) -> f a c -> f a d-gsecond = gfmap---- | Explicitly require a constraint, to force the instantiation of a quantified constraint.-with :: forall c r. (c => r) -> (c => r)-with x = x---- ** Top-level constraints---- *** @gfmap@---- | Constraint for 'gfmap'.-class (forall a. Generic (f a), forall a b. GFunctorRep a b f) => GFunctor f-instance (forall a. Generic (f a), forall a b. GFunctorRep a b f) => GFunctor f---- | Internal component of 'GFunctor'.------ This is an example of the \"quantified constraints trick\" to encode--- @forall a b. GMap1 a b (Rep (f a)) (Rep (f b))@ which doesn't actually--- work as-is.-class GMap1 ((a -> b) :+ ()) (Rep (f a)) (Rep (f b)) => GFunctorRep a b f-instance GMap1 ((a -> b) :+ ()) (Rep (f a)) (Rep (f b)) => GFunctorRep a b f---- *** @gbimap@---- | Constraint for 'gbimap'.-class (forall a c. Generic (f a c), forall a b c d. GBifunctorRep a b c d f) => GBifunctor f-instance (forall a c. Generic (f a c), forall a b c d. GBifunctorRep a b c d f) => GBifunctor f---- | Internal component of 'GBifunctor'.-class GMap1 ((a -> b) :+ (c -> d) :+ ()) (Rep (f a c)) (Rep (f b d)) => GBifunctorRep a b c d f-instance GMap1 ((a -> b) :+ (c -> d) :+ ()) (Rep (f a c)) (Rep (f b d)) => GBifunctorRep a b c d f---- *** @gfirst@---- | Constraint for 'gfirst'.-class (forall a c. Generic (f a c), forall a b c. GFirstRep a b c f) => GFirst f-instance (forall a c. Generic (f a c), forall a b c. GFirstRep a b c f) => GFirst f---- | Internal component of 'GFirst'.-class GMap1 ((a -> b) :+ ()) (Rep (f a c)) (Rep (f b c)) => GFirstRep a b c f-instance GMap1 ((a -> b) :+ ()) (Rep (f a c)) (Rep (f b c)) => GFirstRep a b c f---- *** @gsecond@---- | Constraint for 'gsecond'.-class (forall a c. Generic (f a c), forall a c d. GFunctorRep c d (f a)) => GSecond f-instance (forall a c. Generic (f a c), forall a c d. GFunctorRep c d (f a)) => GSecond f---- *** Others---- | Constraint for 'gsolomap'.-class GMap1 ((a -> b) :+ ()) (Rep x) (Rep y) => GSolomap a b x y-instance GMap1 ((a -> b) :+ ()) (Rep x) (Rep y) => GSolomap a b x y---- | Constraint for 'solomap'.-class Multimap ((a -> b) :+ ()) x y => Solomap a b x y-instance Multimap ((a -> b) :+ ()) x y => Solomap a b x y---- | Constraint for 'gmultimap'.-class GMap1 arr (Rep x) (Rep y) => GMultimap arr x y-instance GMap1 arr (Rep x) (Rep y) => GMultimap arr x y---- | Constraint for 'multimap'.-class Multimap_ (S2 arr) x y => Multimap arr x y-instance Multimap_ (S2 arr) x y => Multimap arr x y---- * Deriving Via---- ** Functor---- | @newtype@ for @DerivingVia@ of 'Functor' instances.------ Note: the GHC extension @DeriveFunctor@ already works out-of-the-box in most--- cases. There are exceptions, such as the following example.------ === Example------ @--- {-\# LANGUAGE DeriveGeneric, DerivingVia \#-}------ import "GHC.Generics" ('Generic')--- import "Generic.Functor" ('DeriveFunctor'(..))------ data Twice a = Twice (Either a a)--- deriving 'Generic'--- deriving 'Functor' via ('DeriveFunctor' Twice)--- @-newtype DeriveFunctor f a = DeriveFunctor (f a)--instance GFunctor f => Functor (DeriveFunctor f) where- fmap = coerce1 (gfmap @f)---- ** Bifunctor---- | @newtype@ for @DerivingVia@ of 'Bifunctor' instances.------ Note: deriving 'Bifunctor' for a generic type often requires 'Functor'--- instances for types mentioned in the fields.------ === Example------ @--- {-\# LANGUAGE DeriveGeneric, DerivingVia \#-}------ import "GHC.Generics" ('Generic')--- import "Generic.Functor" ('DeriveFunctor'(..), 'DeriveBifunctor'(..))------ data Tree a b = Node a (Tree a b) (Tree a b) | Leaf b--- deriving 'Generic'--- deriving 'Functor' via ('DeriveFunctor' (Tree a))--- deriving 'Bifunctor' via ('DeriveBifunctor' Tree)------ data CofreeF f a b = a :< f b--- deriving 'Generic'--- deriving 'Bifunctor' via ('DeriveBifunctor' (CofreeF f))--- @-newtype DeriveBifunctor f a b = DeriveBifunctor (f a b)--instance (GBifunctor f, GFirst f, GSecond f) => Bifunctor (DeriveBifunctor f) where- bimap = coerce2 (gbimap @f)- first = coerce3 (gfirst @f)- second = coerce3 (gsecond @f)---- ** Internal coercions--coerce1 :: Coercible s t => (r -> s) -> (r -> t)-coerce1 = coerce--coerce2 :: Coercible t u => (r -> s -> t) -> (r -> s -> u)-coerce2 = coerce--coerce3 :: (Coercible w v, Coercible (f b d) (g b d)) => (r -> w -> f b d) -> (r -> v -> g b d)-coerce3 = coerce------class GMap1 arr f g where- gmap1 :: arr -> f () -> g ()--instance GMap1 arr f g => GMap1 arr (M1 i c f) (M1 i' c'' g) where- gmap1 = coerce (gmap1 @arr @f @g)--instance (GMap1 arr f1 g1, GMap1 arr f2 g2) => GMap1 arr (f1 :+: f2) (g1 :+: g2) where- gmap1 f (L1 x) = L1 (gmap1 f x)- gmap1 f (R1 x) = R1 (gmap1 f x)--instance (GMap1 arr f1 g1, GMap1 arr f2 g2) => GMap1 arr (f1 :*: f2) (g1 :*: g2) where- gmap1 f (x :*: y) = gmap1 f x :*: gmap1 f y--instance GMap1 arr U1 U1 where- gmap1 _ U1 = U1--instance GMap1 arr V1 V1 where- gmap1 _ v = case v of {}--instance Multimap arr x y => GMap1 arr (K1 i x) (K1 i' y) where- gmap1 = coerce (multimap @arr @x @y)---- | Internal implementation of 'Solomap'.-class Multimap_ arr x y where- multimap_ :: arr -> x -> y---- | Heterogeneous lists of arrows are constructed as lists separated by--- @(':+')@ and terminated by @()@.------ === Example------ Given @f :: a -> a'@ and @g :: b -> b'@,--- @(f ':+' g ':+' ())@ is a list with the two elements @f@ and @g@.------ @--- if--- f :: a -> a'--- g :: b -> b'------ then--- f ':+' g ':+' () :: (a -> a') ':+' (b -> b') ':+' ()--- @------ Those lists are used by 'gmultimap' and 'multimap'.------ @--- bimap_ :: (a -> a') -> (b -> b') -> (Maybe a, [Either b a]) -> (Maybe a', [Either b' a'])--- bimap_ f g = 'multimap' (f ':+' g ':+' ())--- @-data a :+ b = a :+ b-infixr 1 :+---- | @arr@ is the list of arrows provided by the user. It is constant.--- When testing whether any arrow matches, @arr'@ is the remaining list of--- arrows to be tested.-data S arr arr' = S arr arr'--type S2 arr = S arr arr--s2 :: arr -> S2 arr-s2 f = S f f--instance {-# INCOHERENT #-} Multimap_ (S arr ((a -> b) :+ arr')) a b where- multimap_ (S _ (f :+ _)) = f--instance Multimap_ (S arr arr') x y => Multimap_ (S arr ((a -> b) :+ arr')) x y where- multimap_ (S f (_ :+ g')) = multimap_ (S f g')---- "id" instance-instance {-# INCOHERENT #-} Multimap_ (S arr ()) x x where- multimap_ _ = id---- "Functor" instance-instance {-# INCOHERENT #-} (Functor f, Multimap arr x y)- => Multimap_ (S arr ()) (f x) (f y) where- multimap_ (S f ()) = fmap (multimap f)---- Intersection of "id" and "Functor" instances. Prefer "id".--- When both of those instances match then this one should match and avoid an--- unnecessary and overly restrictive Functor constraint.-instance {-# INCOHERENT #-} Multimap_ (S arr ()) (f x) (f x) where- multimap_ _ = id--instance (Multimap arr y1 x1, Multimap arr x2 y2)- => Multimap_ (S arr ()) (x1 -> x2) (y1 -> y2) where- multimap_ (S f ()) u = multimap f . u . multimap f---- "Bifunctor" instance.-instance {-# INCOHERENT #-} (Bifunctor f, Multimap arr x1 y1, Multimap arr x2 y2)- => Multimap_ (S arr ()) (f x1 x2) (f y1 y2) where- multimap_ (S f ()) = bimap (multimap f) (multimap f)---- Intersection of "Bifunctor" and "Functor" instances. Prefer "Functor".-instance {-# INCOHERENT #-} (Functor (f x), Multimap arr x2 y2)- => Multimap_ (S arr ()) (f x x2) (f x y2) where- multimap_ (S f ()) = fmap (multimap f)---- Intersection of "Bifunctor", "Functor", and "id" instances. Prefer "id".-instance {-# INCOHERENT #-} Multimap_ (S arr ()) (f x y) (f x y) where- multimap_ _ = id+{-# LANGUAGE + AllowAmbiguousTypes, + ConstraintKinds, + EmptyCase, + FlexibleContexts, + FlexibleInstances, + MultiParamTypeClasses, + QuantifiedConstraints, + RankNTypes, + ScopedTypeVariables, + TypeApplications, + TypeOperators, + UndecidableInstances #-} + +{-# OPTIONS_GHC -Wno-simplifiable-class-constraints #-} + +-- | This is an internal module. Look, don't touch. +-- +-- "Generic.Functor" is the public API. + +module Generic.Functor.Internal where + +import ApNormalize +import Control.Applicative (liftA2) +import Data.Bifoldable (Bifoldable(..)) +import Data.Bifunctor (Bifunctor(..)) +import Data.Coerce (coerce, Coercible) +import Data.Functor.Identity (Identity(..)) +import Data.Functor.Const (Const(..)) +import Data.Monoid (Endo(..)) +import GHC.Generics hiding (S) + +import Generic.Functor.Internal.Implicit + +-- | Generic implementation of 'fmap'. See also 'GenericFunctor' for @DerivingVia@, +-- using 'gfmap' under the hood. +-- +-- === Example +-- +-- @ +-- {-\# LANGUAGE DeriveGeneric \#-} +-- +-- import "GHC.Generics" ('Generic') +-- import "Generic.Functor" ('gfmap') +-- +-- data Twice a = Twice (Either a a) +-- deriving 'Generic' +-- +-- instance 'Functor' Twice where +-- 'fmap' = 'gfmap' +-- @ +-- +-- Unlike 'gsolomap', 'gfmap' is safe to use in all contexts. +gfmap :: forall f a b. GFunctor f => (a -> b) -> (f a -> f b) +gfmap f = with @(GFunctorRep a b f) (to . gmapRep (defaultIncoherent f) . from) + +-- | Generalized generic functor. +-- +-- 'gsolomap' is a generalization of 'gfmap' (generic 'fmap'), +-- where the type parameter to be \"mapped\" does not have to be the last one. +-- +-- 'gsolomap' is __unsafe__: misuse will break your programs. +-- Read the <#gsolomapusage Usage> section below for details. +-- +-- === Example +-- +-- @ +-- {-\# LANGUAGE DeriveGeneric \#-} +-- +-- import "GHC.Generics" ('Generic') +-- import "Generic.Functor" ('gsolomap') +-- +-- data Result a r = Error a | Ok r -- Another name for Either +-- deriving 'Generic' +-- +-- mapError :: (a -> b) -> Result a r -> Result b r +-- mapError = 'gsolomap' +-- +-- mapOk :: (r -> s) -> Result a r -> Result a s +-- mapOk = 'gsolomap' +-- +-- mapBoth :: (a -> b) -> Result a a -> Result b b +-- mapBoth = 'gsolomap' +-- @ +-- +-- === Usage #gsolomapusage# +-- +-- (This also applies to 'solomap', 'gmultimap', and 'multimap'.) +-- +-- 'gsolomap' should only be used to define __polymorphic__ "@fmap@-like functions". +-- It works only in contexts where @a@ and @b@ are two distinct, non-unifiable +-- type variables. This is usually the case when they are bound by universal +-- quantification (@forall a b. ...@), with no equality constraints on @a@ and +-- @b@. +-- +-- The one guarantee of 'gsolomap' is that @'gsolomap' 'id' = 'id'@. +-- Under the above conditions, that law and the types should uniquely determine +-- the implementation, which 'gsolomap' seeks automatically. +-- +-- The unsafety is due to the use of incoherent instances as part of the +-- definition of 'GSolomap'. Functions are safe to specialize after 'GSolomap' +-- (and 'Solomap') constraints have been discharged. +-- +-- Note also that the type parameters of 'gsolomap' must all be determined by +-- the context. For instance, composing two 'gsolomap', as in +-- @'gsolomap' f . 'gsolomap' g@, is a type error because the type in the middle +-- cannot be inferred. +gsolomap :: forall a b x y. (Generic x, Generic y, GSolomap a b x y) => (a -> b) -> (x -> y) +gsolomap f = to . gmapRep (defaultIncoherent f) . from + +-- | Generalized implicit functor. +-- +-- Use this when @x@ and @y@ are applications of existing functors +-- ('Functor', 'Bifunctor'). +-- +-- This is a different use case from 'gfmap' and 'gsolomap', which make +-- functors out of freshly declared @data@ types. +-- +-- 'solomap' is __unsafe__: misuse will break your programs. +-- +-- See the <#gsolomapusage Usage> section of 'gsolomap' for details. +-- +-- === Example +-- +-- @ +-- map1 :: (a -> b) -> Either e (Maybe [IO a]) -> Either e (Maybe [IO b]) +-- map1 = 'solomap' +-- -- equivalent to: fmap . fmap . fmap . fmap +-- +-- map2 :: (a -> b) -> (e -> Either [a] r) -> (e -> Either [b] r) +-- map2 = 'solomap' +-- -- equivalent to: \\f -> fmap (bimap (fmap f) id) +-- @ +solomap :: forall a b x y. Solomap a b x y => (a -> b) -> (x -> y) +solomap f = multimap f + +-- | Generic n-ary functor. +-- +-- A generalization of 'gsolomap' to map over multiple parameters simultaneously. +-- 'gmultimap' takes a list of functions separated by @(':+')@ and terminated by @()@. +-- +-- 'gmultimap' is __unsafe__: misuse will break your programs. +-- The type of every function in the list must be some @(a -> b)@ +-- where @a@ and @b@ are distinct type variables. +-- +-- See the <#gsolomapusage Usage> section of 'gsolomap' for details. +-- +-- === Example +-- +-- @ +-- {-\# LANGUAGE DeriveGeneric \#-} +-- +-- import "GHC.Generics" ('Generic') +-- import "Generic.Functor" ('gmultimap') +-- +-- data Three a b c = One a | Two b | Three c +-- deriving 'Generic' +-- +-- mapThree :: (a -> a') -> (b -> b') -> (c -> c') -> Three a b c -> Three a' b' c' +-- mapThree f g h = 'gmultimap' (f ':+' g ':+' h ':+' ()) +-- @ +gmultimap :: forall arr x y. (Generic x, Generic y, GMultimap arr x y) => arr -> (x -> y) +gmultimap f = to . gmapRep (defaultIncoherent f) . from + +-- | Implicit n-ary functor. +-- +-- A generalization of 'solomap' to map over multiple parameters simultaneously. +-- 'multimap' takes a list of functions separated by @(':+')@ and terminated by @()@. +-- +-- 'multimap' is __unsafe__: misuse will break your programs. +-- The type of every function in the list must be some @(a -> b)@ +-- where @a@ and @b@ are distinct type variables. +-- +-- See the <#gsolomapusage Usage> section of 'gsolomap' for details. +-- +-- === Example +-- +-- @ +-- type F a b c = Either a (b, c) +-- +-- map3 :: (a -> a') -> (b -> b') -> (c -> c') -> F a b c -> F a' b' c' +-- map3 f g h = 'multimap' (f ':+' g ':+' h ':+' ()) +-- -- equivalent to: \\f g h -> bimap f (bimap g h) +-- @ +multimap :: forall arr x y. Multimap arr x y => arr -> (x -> y) +multimap f = multimapI (defaultIncoherent f) + +-- | Generic implementation of 'bimap' from 'Bifunctor'. See also 'GenericBifunctor'. +gbimap :: forall f a b c d. GBimap f => (a -> b) -> (c -> d) -> f a c -> f b d +gbimap f g = with @(GBimapRep a b c d f) (to . gmapRep (defaultIncoherent (f :+ g)) . from) + +-- | Generic implementation of 'first' from 'Bifunctor'. See also 'GenericBifunctor'. +gfirst :: forall f a b c. GFirst f => (a -> b) -> f a c -> f b c +gfirst f = with @(GFirstRep a b c f) (to . gmapRep (defaultIncoherent f) . from) + +-- | Generic implementation of 'second' from 'Bifunctor'. See also 'GenericBifunctor'. +gsecond :: forall f a c d. GSecond f => (c -> d) -> f a c -> f a d +gsecond = gfmap + +-- *** Fold + +-- | Generic implementation of 'foldMap' from 'Foldable'. +gfoldMap :: forall t m a. (GFoldMap m t, Monoid m) => (a -> m) -> t a -> m +gfoldMap f = + with @(GFoldMapRep a a m t) (gfoldMapRep (defaultIncoherent (Fold @m @a @a f)) . from) + +-- | Generic implementation of 'bifoldMap' from 'Bifoldable'. +gbifoldMap :: forall t m a b. (GBifoldMap m t, Monoid m) => (a -> m) -> (b -> m) -> t a b -> m +gbifoldMap f g = + with @(GBifoldMapRep a a b b m t) (gfoldMapRep (defaultIncoherent (Fold @m @a @a f :+ Fold @m @b @b g)) . from) + +-- *** Traverse + +-- | Generic implementation of 'traverse' from 'Traversable'. +gtraverse :: forall t f a b. (GTraverse f t, Applicative f) => (a -> f b) -> t a -> f (t b) +gtraverse f = with @(GTraverseRep a b f t) (lowerAps . fmap to . gtraverseRep (defaultIncoherent f) . from) + +-- | Generic implementation of 'bitraverse' from 'Bitraversable'. +gbitraverse :: forall t f a b c d. (GBitraverse f t, Applicative f) => (a -> f b) -> (c -> f d) -> t a c -> f (t b d) +gbitraverse f g = + with @(GBitraverseRep a b c d f t) (lowerAps . fmap to . gtraverseRep (defaultIncoherent (f :+ g)) . from) + + +-- | Explicitly require a constraint, to force the instantiation of a quantified constraint. +with :: forall c r. (c => r) -> (c => r) +with x = x + +-- ** Top-level constraints + +-- *** @gfmap@ + +-- | Generic 'Functor'. Constraint for 'gfmap'. +class (forall a. Generic (f a), forall a b. GFunctorRep a b f) => GFunctor f +instance (forall a. Generic (f a), forall a b. GFunctorRep a b f) => GFunctor f + +-- | Internal component of 'GFunctor'. +-- +-- This is an example of the \"quantified constraints trick\" to encode +-- @forall a b. GMap1 a b (Rep (f a)) (Rep (f b))@ which doesn't actually +-- work as-is. +class GMap1 (Default Incoherent (a -> b)) (Rep (f a)) (Rep (f b)) => GFunctorRep a b f +instance GMap1 (Default Incoherent (a -> b)) (Rep (f a)) (Rep (f b)) => GFunctorRep a b f + +-- *** @gbimap@ + +-- | Constraint for 'gbimap'. +class (forall a c. Generic (f a c), forall a b c d. GBimapRep a b c d f) => GBimap f +instance (forall a c. Generic (f a c), forall a b c d. GBimapRep a b c d f) => GBimap f + +-- | Internal component of 'GBifunctor'. +class GMap1 (Default Incoherent ((a -> b) :+ (c -> d))) (Rep (f a c)) (Rep (f b d)) => GBimapRep a b c d f +instance GMap1 (Default Incoherent ((a -> b) :+ (c -> d))) (Rep (f a c)) (Rep (f b d)) => GBimapRep a b c d f + +-- *** @gfirst@ + +-- | Constraint for 'gfirst'. +class (forall a c. Generic (f a c), forall a b c. GFirstRep a b c f) => GFirst f +instance (forall a c. Generic (f a c), forall a b c. GFirstRep a b c f) => GFirst f + +-- | Internal component of 'GFirst'. +class GMap1 (Default Incoherent (a -> b)) (Rep (f a c)) (Rep (f b c)) => GFirstRep a b c f +instance GMap1 (Default Incoherent (a -> b)) (Rep (f a c)) (Rep (f b c)) => GFirstRep a b c f + +-- *** @gsecond@ + +-- | Constraint for 'gsecond'. +class (forall a c. Generic (f a c), forall a c d. GFunctorRep c d (f a)) => GSecond f +instance (forall a c. Generic (f a c), forall a c d. GFunctorRep c d (f a)) => GSecond f + +-- | Generic 'Bifunctor'. +class (GBimap f, GFirst f, GSecond f) => GBifunctor f +instance (GBimap f, GFirst f, GSecond f) => GBifunctor f + +-- *** @gtraverse@ + +-- | Constraint for 'gtraverse'. +class (forall a. Generic (t a), forall a b. GTraverseRep a b f t) => GTraverse f t +instance (forall a. Generic (t a), forall a b. GTraverseRep a b f t) => GTraverse f t + +class GTraverse1 f (Default Incoherent (a -> f b)) (Rep (t a)) (Rep (t b)) => GTraverseRep a b f t +instance GTraverse1 f (Default Incoherent (a -> f b)) (Rep (t a)) (Rep (t b)) => GTraverseRep a b f t + +-- | Generic 'Traversable'. +class (forall f. Applicative f => GBitraverse f t) => GTraversable t +instance (forall f. Applicative f => GBitraverse f t) => GTraversable t + +-- | Constraint for 'gtraverse'. +class (forall a b. Generic (t a b), forall a b c d. GBitraverseRep a b c d f t) => GBitraverse f t +instance (forall a b. Generic (t a b), forall a b c d. GBitraverseRep a b c d f t) => GBitraverse f t + +class GTraverse1 f (Default Incoherent ((a -> f b) :+ (c -> f d))) (Rep (t a c)) (Rep (t b d)) => GBitraverseRep a b c d f t +instance GTraverse1 f (Default Incoherent ((a -> f b) :+ (c -> f d))) (Rep (t a c)) (Rep (t b d)) => GBitraverseRep a b c d f t + +-- | Generic 'Bitraversable'. +class (forall f. Applicative f => GBitraverse f t) => GBitraversable t +instance (forall f. Applicative f => GBitraverse f t) => GBitraversable t + +-- *** @foldMap@ + +-- | Constraint for 'gfoldMap'. +class (forall a. Generic (t a), forall a b. GFoldMapRep a b m t) => GFoldMap m t +instance (forall a. Generic (t a), forall a b. GFoldMapRep a b m t) => GFoldMap m t + +class GFoldMap1 m (Default Incoherent (Fold m a b)) (Rep (t a)) (Rep (t b)) => GFoldMapRep a b m t +instance GFoldMap1 m (Default Incoherent (Fold m a b)) (Rep (t a)) (Rep (t b)) => GFoldMapRep a b m t + +-- | Generic 'Foldable'. Constraint for 'GenericFunctor' (deriving-via 'Foldable'). +class (forall m. Monoid m => GFoldMap m t) => GFoldable t +instance (forall m. Monoid m => GFoldMap m t) => GFoldable t + +-- | Constraint for 'gbifoldMap'. +class (forall a b. Generic (t a b), forall a b c d. GBifoldMapRep a b c d m t) => GBifoldMap m t +instance (forall a b. Generic (t a b), forall a b c d. GBifoldMapRep a b c d m t) => GBifoldMap m t + +class GFoldMap1 m (Default Incoherent (Fold m a b :+ Fold m c d)) (Rep (t a c)) (Rep (t b d)) => GBifoldMapRep a b c d m t +instance GFoldMap1 m (Default Incoherent (Fold m a b :+ Fold m c d)) (Rep (t a c)) (Rep (t b d)) => GBifoldMapRep a b c d m t + +-- | Generic 'Foldable'. Constraint for 'GenericFunctor' (deriving-via 'Foldable'). +class (forall m. Monoid m => GBifoldMap m t) => GBifoldable t +instance (forall m. Monoid m => GBifoldMap m t) => GBifoldable t + +-- *** Others + +-- | Constraint for 'gsolomap'. +class GMultimap (a -> b) x y => GSolomap a b x y +instance GMultimap (a -> b) x y => GSolomap a b x y + +-- | Constraint for 'solomap'. +class Multimap (a -> b) x y => Solomap a b x y +instance Multimap (a -> b) x y => Solomap a b x y + +-- | Constraint for 'gmultimap'. +class GMap1 (Default Incoherent arr) (Rep x) (Rep y) => GMultimap arr x y +instance GMap1 (Default Incoherent arr) (Rep x) (Rep y) => GMultimap arr x y + +-- | Constraint for 'multimap'. +class MultimapI (Default Incoherent arr) x y => Multimap arr x y +instance MultimapI (Default Incoherent arr) x y => Multimap arr x y + +-- * Deriving Via + +-- ** Functor + +-- | @newtype@ for @DerivingVia@ of 'Functor' and 'Foldable' instances. +-- +-- Note: the GHC extensions @DeriveFunctor@, @DeriveFoldable@, and @DeriveTraversable@ +-- (which implies all three) already works out-of-the-box in most cases. +-- There are exceptions, such as the following example. +-- +-- === Example +-- +-- @ +-- {-\# LANGUAGE DeriveGeneric, DerivingVia \#-} +-- +-- import "GHC.Generics" ('Generic') +-- import "Generic.Functor" ('GenericFunctor'(..)) +-- +-- data Twice a = Twice (Either a a) +-- deriving 'Generic' +-- deriving ('Functor', 'Foldable') via ('GenericFunctor' Twice) +-- @ +newtype GenericFunctor f a = GenericFunctor (f a) + +instance GFunctor f => Functor (GenericFunctor f) where + fmap = coerce1 (gfmap @f) + +instance GFoldable f => Foldable (GenericFunctor f) where + foldMap = coerceFoldMap (gfoldMap @f) + +-- ** Bifunctor + +-- | @newtype@ for @DerivingVia@ of 'Bifunctor' and 'Bifoldable' instances. +-- +-- Note: deriving 'Bifunctor' for a generic type often requires 'Functor' +-- instances for types mentioned in the fields. +-- +-- === Example +-- +-- @ +-- {-\# LANGUAGE DeriveGeneric, DerivingVia \#-} +-- +-- import "Data.Bifoldable" ('Bifoldable') +-- import "Data.Bifunctor" ('Bifunctor') +-- import "GHC.Generics" ('Generic') +-- import "Generic.Functor" ('GenericFunctor'(..), 'GenericBifunctor'(..)) +-- +-- data Tree a b = Node a (Tree a b) (Tree a b) | Leaf b +-- deriving 'Generic' +-- deriving ('Functor', 'Foldable') via ('GenericFunctor' (Tree a)) +-- deriving ('Bifunctor', 'Bifoldable') via ('GenericBifunctor' Tree) +-- +-- data CofreeF f a b = a :< f b +-- deriving 'Generic' +-- deriving ('Bifunctor', 'Bifoldable') via ('GenericBifunctor' (CofreeF f)) +-- @ +newtype GenericBifunctor f a b = GenericBifunctor (f a b) + +instance GBifunctor f => Bifunctor (GenericBifunctor f) where + bimap = coerce2 (gbimap @f) + first = coerce3 (gfirst @f) + second = coerce3 (gsecond @f) + +instance GBifoldable f => Bifoldable (GenericBifunctor f) where + bifoldMap = coerceBifoldMap (gbifoldMap @f) + +-- ** Internal coercions + +coerce1 :: Coercible s t => (r -> s) -> (r -> t) +coerce1 = coerce + +coerce2 :: Coercible t u => (r -> s -> t) -> (r -> s -> u) +coerce2 = coerce + +coerce3 :: (Coercible w v, Coercible (f b d) (g b d)) => (r -> w -> f b d) -> (r -> v -> g b d) +coerce3 = coerce + +coerceFoldMap :: Coercible t u => (am -> t -> m) -> (am -> u -> m) +coerceFoldMap = coerce + +coerceBifoldMap :: Coercible t u => (am -> bm -> t -> m) -> (am -> bm -> u -> m) +coerceBifoldMap = coerce + +-- ** @GMultimapK@ + +-- | We use the same class to implement all of 'fmap', 'foldMap', 'traverse', +-- instantiating @m@ as 'Identity', 'Const (EndoM mm)' and 'Aps n' respectively. +-- Those three cases differ in their instances for 'K1'. +-- +-- (the K stands for @Kleisli@, because the result is @Kleisli m (f ()) (g ())@ +class GMultimapK m arr f g where + gmultimapK :: arr -> f () -> m (g ()) + +-- *** Instance for @fmap@ + +instance MultimapI arr x y => GMultimapK Identity arr (K1 i x) (K1 i' y) where + gmultimapK = coerce (multimapI @arr @x @y) + +class GMultimapK Identity arr f g => GMap1 arr f g +instance GMultimapK Identity arr f g => GMap1 arr f g + +gmapRep :: GMap1 arr f g => arr -> f () -> g () +gmapRep f x = runIdentity (gmultimapK f x) + +-- *** Instance for @foldMap@ + +instance (Multifold_ m arr x y, Monoid m) => GMultimapK (Const (EndoM m)) arr (K1 i x) (K1 i' y) where + gmultimapK f (K1 x) = K1 <$> foldToConst (multifold_ f) x + +-- Spooky instance. It makes sense only because @GMultimapK (Const (EndoM m))@ +-- occurs exclusively under a quantified constraint (in the definition of GFoldMap). +instance {-# INCOHERENT #-} GMultimapK (Const (EndoM m)) arr (K1 i x) (K1 i x) where + gmultimapK _ (K1 _) = Const (Endo id) + +-- An extra wrapper to simplify away @(mempty <> _)@ and @(_ <> mempty)@. +type EndoM m = Endo (Maybe m) + +unEndoM :: Monoid m => EndoM m -> m +unEndoM (Endo f) = case f Nothing of + Nothing -> mempty + Just y -> y + +liftEndoM :: Monoid m => m -> EndoM m +liftEndoM y = Endo (Just . app) + where + app Nothing = y + app (Just y') = y `mappend` y' + +foldToConst :: Monoid m => Fold m x y -> x -> Const (EndoM m) y +foldToConst (Fold f) x = Const (liftEndoM (f x)) + +class GMultimapK (Const (EndoM m)) arr f g => GFoldMap1 m arr f g +instance GMultimapK (Const (EndoM m)) arr f g => GFoldMap1 m arr f g + +-- | Danger! @GFoldMap1 m arr f f@ MUST come from a quantified constraint (see use in 'gfoldMap'). +gfoldMapRep :: forall m arr f. (GFoldMap1 m arr f f, Monoid m) => arr -> f () -> m +gfoldMapRep f x = unEndoM (getConst (gmultimapK f x :: Const (EndoM m) (f ()))) + +-- *** Instance for @traverse@ + +instance (Multitraverse m arr x y) => GMultimapK (Aps m) arr (K1 i x) (K1 i' y) where + gmultimapK f (K1 x) = K1 <$>^ multitraverse f x + +class GMultimapK (Aps m) arr f g => GTraverse1 m arr f g +instance GMultimapK (Aps m) arr f g => GTraverse1 m arr f g + +gtraverseRep :: GTraverse1 m arr f g => arr -> f () -> Aps m (g ()) +gtraverseRep = gmultimapK + +-- *** Common instances + +instance (GMultimapK m arr f g, Functor m) => GMultimapK m arr (M1 i c f) (M1 i' c' g) where + gmultimapK f (M1 x) = M1 <$> gmultimapK f x + +instance + (GMultimapK m arr f1 g1, GMultimapK m arr f2 g2, Applicative m) => + GMultimapK m arr (f1 :+: f2) (g1 :+: g2) + where + gmultimapK f (L1 x) = L1 <$> gmultimapK f x + gmultimapK f (R1 y) = R1 <$> gmultimapK f y + +instance + (GMultimapK m arr f1 g1, GMultimapK m arr f2 g2, Applicative m) => + GMultimapK m arr (f1 :*: f2) (g1 :*: g2) + where + gmultimapK f (x :*: y) = liftA2 (:*:) (gmultimapK f x) (gmultimapK f y) + +instance Applicative m => GMultimapK m arr U1 U1 where + gmultimapK _ U1 = pure U1 + +instance GMultimapK m arr V1 V1 where + gmultimapK _ v = case v of
+ src/Generic/Functor/Internal/Implicit.hs view
@@ -0,0 +1,225 @@+{-# LANGUAGE + ConstraintKinds, + FlexibleContexts, + FlexibleInstances, + InstanceSigs, + MultiParamTypeClasses, + RankNTypes, + ScopedTypeVariables, + TypeApplications, + TypeFamilies, + TypeOperators, + UndecidableInstances #-} +{-# OPTIONS_GHC -Wno-simplifiable-class-constraints #-} + +module Generic.Functor.Internal.Implicit where + +import Control.Arrow (Kleisli (..)) +import Data.Bifunctor (Bifunctor (..)) +import Data.Bifoldable (Bifoldable (..)) +import Data.Bitraversable (Bitraversable (..)) +import Data.Coerce (Coercible, coerce) +import Data.Kind (Type) + +-- | Core of 'multimap' +multimapI :: forall arr x y. MultimapI arr x y => arr -> (x -> y) +multimapI = multimapOf + +multitraverse :: forall f arr x y. Multitraverse f arr x y => arr -> (x -> f y) +multitraverse f = runKleisli (multimapOf (coerce f :: WrapKleisli f arr)) + +-- | This is kept internal because of the 'Fold' wrapping. +multifold_ :: forall m arr x y. Multifold_ m arr x y => arr -> Fold m x y +multifold_ = multimapOf + +multimapOf :: forall cat arr x y. MultimapOf cat arr x y => arr -> cat x y +multimapOf f = multimap_ (s2 f) + +-- | Core of 'multimap'. +class MultimapOf (->) arr x y => MultimapI arr x y +instance MultimapOf (->) arr x y => MultimapI arr x y + +-- | Constraint for 'multifold_'. +class MultimapOf (Fold m) arr x y => Multifold_ m arr x y +instance MultimapOf (Fold m) arr x y => Multifold_ m arr x y + +-- | Constraint for 'multitraverse'. +class Multitraverse_ f arr x y => Multitraverse f arr x y +instance Multitraverse_ f arr x y => Multitraverse f arr x y + +-- | Internal definition of 'Multitraverse' +type Multitraverse_ f arr x y = + ( MultimapOf (Kleisli f) (WrapKleisli f arr) x y, + CoercibleKleisli f (WrapKleisli f arr) arr + ) + +type family WrapKleisli (f :: Type -> Type) (arr :: Type) +type instance WrapKleisli _f NilArr = NilArr +type instance WrapKleisli _f (Rule rule mode)= Rule rule mode +type instance WrapKleisli f (a :+ arr) = WrapKleisli f a :+ WrapKleisli f arr +type instance WrapKleisli f (a -> f b) = Kleisli f a b + +-- | Auxiliary constraint for 'Multitraverse' +class Coercible warr arr => CoercibleKleisli (f :: Type -> Type) warr arr +instance (d ~ NilArr) => CoercibleKleisli f d NilArr +instance (d ~ Rule rule mode) => CoercibleKleisli f d (Rule rule mode) +instance (CoercibleKleisli f a b, CoercibleKleisli f arr arr') => CoercibleKleisli f (a :+ arr) (b :+ arr') +instance (b2 ~ f c, a ~ Kleisli f b1 c) => CoercibleKleisli f a (b1 -> b2) + +class Multimap_ cat (S2 arr) x y => MultimapOf cat arr x y +instance Multimap_ cat (S2 arr) x y => MultimapOf cat arr x y + +-- | @Fold m@ is like @Kleisli (Const m)@, but it has a different @FunctorOf@ instance, +-- with 'Foldable' instead of 'Traversable'. +newtype Fold m x y = Fold { unFold :: x -> m } + +instance Monoid m => CatLike (Fold m) where + catid = Fold (\_ -> mempty) + +instance (Foldable t, Monoid m) => FunctorOf (Fold m) t where + catmap (Fold f) = Fold (foldMap f) + +instance (Bifoldable t, Monoid m) => BifunctorOf (Fold m) t where + catbimap (Fold f) (Fold g) = Fold (bifoldMap f g) + +-- * Internal + +class CatLike cat where + catid :: cat x x + +instance CatLike (->) where + catid = id + +instance Applicative f => CatLike (Kleisli f) where + catid = Kleisli pure + +class FunctorOf cat t where + catmap :: cat a b -> cat (t a) (t b) + +instance Functor t => FunctorOf (->) t where + catmap = fmap + +instance (Applicative f, Traversable t) => FunctorOf (Kleisli f) t where + catmap :: forall a b. Kleisli f a b -> Kleisli f (t a) (t b) + catmap = coerce (traverse @t @f @a @b) + +class BifunctorOf cat t where + catbimap :: cat a b -> cat c d -> cat (t a c) (t b d) + +instance Bifunctor t => BifunctorOf (->) t where + catbimap = bimap + +instance (Applicative f, Bitraversable t) => BifunctorOf (Kleisli f) t where + catbimap :: forall a b c d. Kleisli f a b -> Kleisli f c d -> Kleisli f (t a c) (t b d) + catbimap = coerce (bitraverse @t @f @a @b @c @d) + +-- | Internal implementation of 'MultimapOf'. +class Multimap_ cat arr x y where + multimap_ :: arr -> cat x y + +-- | Heterogeneous lists of arrows are constructed as lists separated by +-- @(':+')@ and terminated by @()@. +-- +-- === Example +-- +-- Given @f :: a -> a'@ and @g :: b -> b'@, +-- @(f ':+' g ':+' ())@ is a list with the two elements @f@ and @g@. +-- +-- @ +-- if +-- f :: a -> a' +-- g :: b -> b' +-- +-- then +-- f ':+' g ':+' () :: (a -> a') ':+' (b -> b') ':+' () +-- @ +-- +-- Those lists are used by 'gmultimap' and 'multimap'. +-- +-- @ +-- bimap_ :: (a -> a') -> (b -> b') -> (Maybe a, [Either b a]) -> (Maybe a', [Either b' a']) +-- bimap_ f g = 'multimap' (f ':+' g ':+' ()) +-- @ +data a :+ b = a :+ b + +infixr 1 :+ + +-- Special arrows + +data Rule rule mode = Rule rule mode +data AnyId = AnyId +data AnyFunctor = AnyFunctor +data AnyBifunctor = AnyBifunctor +data NilArr = NilArr + +data Incoherent = Incoherent + +type Default mode arr = arr :+ Rule AnyId mode :+ Rule AnyFunctor mode :+ Rule AnyBifunctor mode :+ NilArr + +defaultIncoherent :: arr -> Default Incoherent arr +defaultIncoherent = def Incoherent + +def :: mode -> arr -> Default mode arr +def mode arr = arr :+ Rule AnyId mode :+ Rule AnyFunctor mode :+ Rule AnyBifunctor mode :+ NilArr + +-- | @arr@ is the list of arrows provided by the user. It is constant. +-- When testing whether any arrow matches, @arr'@ is the remaining list of +-- arrows to be tested. +data S arr arr' = S arr arr' + +type S2 arr = S arr arr + +s2 :: arr -> S2 arr +s2 f = S f f + +-- The head doesn't match anything, go to the next thing. +instance {-# OVERLAPPABLE #-} Multimap_ cat (S arr arr') x y => Multimap_ cat (S arr (arr0 :+ arr')) x y where + multimap_ (S f (_ :+ g')) = multimap_ (S f g') + +-- Reassociate to even handle tree-shaped parameters. +instance Multimap_ cat (S arr (arr0 :+ arr1 :+ arr2)) x y => Multimap_ cat (S arr ((arr0 :+ arr1) :+ arr2)) x y where + multimap_ (S f ((f0 :+ f1) :+ f2)) = multimap_ (S f (f0 :+ f1 :+ f2)) + +instance Multimap_ cat (S arr arr') x y => Multimap_ cat (S arr (NilArr :+ arr')) x y where + multimap_ (S f (NilArr :+ f')) = multimap_ (S f f') + +instance Multimap_ cat (S arr arr') x y => Multimap_ cat (S arr (() :+ arr')) x y where + multimap_ (S f (() :+ f')) = multimap_ (S f f') + +instance {-# INCOHERENT #-} Multimap_ cat (S arr (cat a b :+ arr')) a b where + multimap_ (S _ (f :+ _)) = f + +-- "id" instance +instance {-# INCOHERENT #-} CatLike cat => Multimap_ cat (S arr (Rule AnyId Incoherent :+ arr')) x x where + multimap_ _ = catid + +-- "Functor" instance +-- Note: if x ~ y, then @AnyId Incoherent@ should already have matched earlier +-- (if you remembered to put it in the list), +-- so we don't need another overlapping instance here. +instance + {-# INCOHERENT #-} + (FunctorOf cat f, MultimapOf cat arr x y) => + Multimap_ cat (S arr (Rule AnyFunctor Incoherent :+ arr')) (f x) (f y) + where + multimap_ (S f (Rule AnyFunctor Incoherent :+ _)) = catmap (multimapOf f) + +-- "Bifunctor" instance. +-- Note: the overlap with AnyId (where x1 ~ y1, x2 ~ y2) and AnyFunctor (where x1 ~ x2) +-- is handled by putting those rules before AnyBifunctor in the list. +instance + {-# INCOHERENT #-} + (BifunctorOf cat f, MultimapOf cat arr x1 y1, MultimapOf cat arr x2 y2) => + Multimap_ cat (S arr (Rule AnyBifunctor Incoherent :+ arr')) (f x1 x2) (f y1 y2) + where + multimap_ (S f (Rule AnyBifunctor Incoherent :+ _)) = catbimap (multimapOf f) (multimapOf f) + +-- Hardcoded special case for (->) +-- We know how to "Multimap_ (->)" over (->), +-- not "Multimap_ (Kleisli f)". +instance + {-# INCOHERENT #-} + (MultimapOf (->) arr y1 x1, MultimapOf (->) arr x2 y2) => + Multimap_ (->) (S arr (Rule AnyBifunctor Incoherent :+ arr')) (x1 -> x2) (y1 -> y2) + where + multimap_ (S f (Rule AnyBifunctor Incoherent :+ _)) u = multimapOf f . u . multimapOf f
test/test.hs view
@@ -1,139 +1,220 @@-{-# LANGUAGE- DeriveGeneric,- DerivingVia #-}--import Data.Bifunctor-import GHC.Generics-import Generic.Functor-import System.Exit (exitFailure)---- Testing DeriveFunctor (gfmap) and gsolomap--data Empty a- deriving Generic- deriving Functor via (DeriveFunctor Empty)--data Unit a = Unit- deriving (Eq, Show, Generic)- deriving Functor via (DeriveFunctor Unit)--data Result a r = Error a | Ok r- deriving (Eq, Show, Generic)- deriving Functor via (DeriveFunctor (Result a))- -mapError :: (a -> b) -> Result a r -> Result b r-mapError = gsolomap--mapOk :: (r -> s) -> Result a r -> Result a s-mapOk = gsolomap--mapBoth :: (a -> b) -> Result a a -> Result b b-mapBoth = gsolomap--data Writer w a = Writer w a- deriving (Eq, Show, Generic)- deriving Functor via (DeriveFunctor (Writer w))--mapW :: (w -> w') -> Writer w a -> Writer w' a-mapW = gsolomap--data Square a b = Square a a b b- deriving (Eq, Show, Generic)- deriving Functor via (DeriveFunctor (Square a))--mapFirst :: (a -> a') -> Square a b -> Square a' b-mapFirst = gsolomap--data Twice a = Twice (Either a a)- deriving (Eq, Show, Generic)- deriving Functor via (DeriveFunctor Twice)---- Testing solomap--map1, map1' :: (a -> b) -> Either e (Maybe [(e, a)]) -> Either e (Maybe [(e, b)])-map1 = solomap-map1' = fmap . fmap . fmap . fmap -- equivalent definition, just making sure it typechecks--map2, map2' :: (a -> b) -> (e -> Either [a] r) -> (e -> Either [b] r)-map2 = solomap-map2' f = fmap (bimap (fmap f) id)--type F a = ([a], Either a ())--map3, map3' :: (a -> b) -> F a -> F b-map3 = solomap-map3' f = bimap (fmap f) (bimap f id)--type G t a = (t, Maybe [Either Bool a])--map4 :: (a -> b) -> G t a -> G t b-map4 = solomap-map4' = fmap . fmap . fmap . fmap---- Deriving Bifunctor--data Tree a b = Node a (Tree a b) (Tree a b) | Leaf b- deriving (Eq, Show, Generic)- deriving Functor via (DeriveFunctor (Tree a))- deriving Bifunctor via (DeriveBifunctor Tree)--data CofreeF f a b = a :< f b- deriving (Eq, Show, Generic)- deriving Bifunctor via (DeriveBifunctor (CofreeF f))---- Multimap--data Three a b c = One a | Two b | Three c- deriving (Eq, Show, Generic)--mapThree :: (a -> a') -> (b -> b') -> (c -> c') -> Three a b c -> Three a' b' c'-mapThree f g h = gmultimap (f :+ g :+ h :+ ())--type F5 a b c = Either a (b, c)--map5 :: (a -> a') -> (b -> b') -> (c -> c') -> F5 a b c -> F5 a' b' c'-map5 f g h = multimap (f :+ g :+ h :+ ())-map5' f g h = bimap f (bimap g h)---- Run at least once--twice :: Int -> Int-twice = (* 2)--main :: IO ()-main = do- Unit @= fmap twice Unit- Ok 8 @= fmap twice (Ok 4 :: Result () Int)- Error 8 @= mapError twice (Error 4 :: Result Int ())- Writer () 8 @= fmap twice (Writer () 4)- Writer 8 () @= mapW twice (Writer 4 ())- Square () () 8 10 @= fmap twice (Square () () 4 5)- Square 8 10 () () @= mapFirst twice (Square 4 5 () ())- [Twice (Left 8), Twice (Right 10)] @= (fmap . fmap) twice [Twice (Left 4), Twice (Right 5)]- Node 8 (Leaf 10) (Leaf 12) @= bimap twice twice (Node 4 (Leaf 5) (Leaf 6))- (8 :< Just 10) @= bimap twice twice (4 :< Just 5)- [One 8, Two False, Three 1] @= fmap (mapThree twice not length) [One 4, Two True, Three [()]]-- let t1 = Right (Just [((), 4)])- map1 twice t1 @= map1' twice t1-- let t2 x = Left [x] :: Either [Int] ()- map2 twice t2 4 @= map2' twice t2 4-- let t3 = ([4], Left 5)- map3 twice t3 @= map3' twice t3-- let t4 = ((), Just [Right 4])- map4 twice t4 @= map4' twice t4-- let t5 = [Left 4, Right (False, [()])]- fmap (map5 twice not length) t5 @= fmap (map5 twice not length) t5---- Assert equality-(@=) :: (Eq a, Show a) => a -> a -> IO ()-(@=) x y | x == y = pure ()- | otherwise = do- putStrLn "Not equal:"- print x- print y- exitFailure+{-# LANGUAGE + DeriveFoldable, + DeriveGeneric, + DerivingVia, + StandaloneDeriving, + TypeOperators #-} + +import Control.Monad.Trans.State ( evalState, state, State ) +import Data.Bifoldable ( Bifoldable() ) +import Data.Bifunctor ( Bifunctor(bimap) ) +import GHC.Generics ( Generic ) +import System.Exit (exitFailure) + +import Generic.Functor + ( gmultimap, + gsolomap, + gtraverse, + multimap, + solomap, + GenericBifunctor(..), + GenericFunctor(..), + type (:+)((:+)) ) + +-- Testing GenericFunctor (gfmap) and gsolomap + +data Empty a + deriving Generic + deriving (Functor, Foldable) via (GenericFunctor Empty) + +data Unit a = Unit + deriving (Eq, Show, Generic) + deriving (Functor, Foldable) via (GenericFunctor Unit) + +data Result a r = Error a | Ok r + deriving (Eq, Show, Generic) + deriving (Functor, Foldable) via (GenericFunctor (Result a)) + +instance Traversable Empty where + traverse = gtraverse + +instance Traversable Unit where + traverse = gtraverse + +instance Traversable (Result a) where + traverse = gtraverse + +mapError :: (a -> b) -> Result a r -> Result b r +mapError = gsolomap + +mapOk :: (r -> s) -> Result a r -> Result a s +mapOk = gsolomap + +mapBoth :: (a -> b) -> Result a a -> Result b b +mapBoth = gsolomap + +data Writer w a = Writer w a + deriving (Eq, Show, Generic) + deriving (Functor, Foldable) via (GenericFunctor (Writer w)) + +instance Traversable (Writer w) where + traverse = gtraverse + +mapW :: (w -> w') -> Writer w a -> Writer w' a +mapW = gsolomap + +data Square a b = Square a a b b + deriving (Eq, Show, Generic) + deriving (Functor, Foldable) via (GenericFunctor (Square a)) + +instance Traversable (Square a) where + traverse = gtraverse + +mapFirst :: (a -> a') -> Square a b -> Square a' b +mapFirst = gsolomap + +data Twice a = Twice (Either a a) + deriving (Eq, Show, Generic) + deriving (Functor, Foldable) via (GenericFunctor Twice) + +instance Traversable Twice where + traverse = gtraverse + +-- Testing solomap + +map1, map1' :: (a -> b) -> Either e (Maybe [(e, a)]) -> Either e (Maybe [(e, b)]) +map1 = solomap +map1' = fmap . fmap . fmap . fmap -- equivalent definition, just making sure it typechecks + +map2, map2' :: (a -> b) -> (e -> Either [a] r) -> (e -> Either [b] r) +map2 = solomap +map2' f = fmap (bimap (fmap f) id) + +type F a = ([a], Either a ()) + +map3, map3' :: (a -> b) -> F a -> F b +map3 = solomap +map3' f = bimap (fmap f) (bimap f id) + +type G t a = (t, Maybe [Either Bool a]) + +map4, map4', map4'' :: (a -> b) -> G t a -> G t b +map4 = solomap +map4' = fmap . fmap . fmap . fmap +map4'' = multimap + +map6, map6' :: (a -> b) -> (c -> d) -> G a c -> G b d +map6 f g = multimap (f :+ g) +map6' f = bimap f . fmap . fmap . fmap + +-- Deriving Bifunctor + +data Tree a b = Node a (Tree a b) (Tree a b) | Leaf b + deriving (Eq, Show, Generic) + deriving (Functor, Foldable) via (GenericFunctor (Tree a)) + deriving (Bifunctor, Bifoldable) via (GenericBifunctor Tree) + +instance Traversable (Tree a) where + traverse = gtraverse + +data CofreeF f a b = a :< f b + deriving (Eq, Show, Generic) + deriving (Bifunctor, Bifoldable) via (GenericBifunctor (CofreeF f)) + +deriving via GenericFunctor (CofreeF f a) instance Foldable f => Foldable (CofreeF f a) +deriving via GenericFunctor (CofreeF f a) instance Functor f => Functor (CofreeF f a) + +instance Traversable f => Traversable (CofreeF f a) where + traverse = gtraverse + +bimapCofreeF' :: Functor f => (a -> b) -> (c -> d) -> CofreeF f a c -> CofreeF f b d +bimapCofreeF' f g = gmultimap (f :+ g) + +-- Multimap + +data Three a b c = One a | Two b | Three c + deriving (Eq, Show, Generic) + deriving (Functor, Foldable) via (GenericFunctor (Three a b)) + +instance Traversable (Three a b) where + traverse = gtraverse + +mapThree :: (a -> a') -> (b -> b') -> (c -> c') -> Three a b c -> Three a' b' c' +mapThree f g h = gmultimap (f :+ g :+ h) + +type F5 a b c = Either a (b, c) + +map5, map5' :: (a -> a') -> (b -> b') -> (c -> c') -> F5 a b c -> F5 a' b' c' +map5 f g h = multimap (f :+ g :+ h) +map5' f g h = bimap f (bimap g h) + +-- Run at least once + +twice :: Int -> Int +twice = (* 2) + +foldTest :: Foldable t => t Int -> Int +foldTest = sum -- specialized + +tick :: Int -> State Int Int +tick _ = state (\i -> (i, i+1)) + +travTest :: Traversable t => t Int -> t Int +travTest = (`evalState` 0) . traverse tick + +main :: IO () +main = do + Unit @= fmap twice Unit + Ok 8 @= fmap twice (Ok 4 :: Result () Int) + Error 8 @= mapError twice (Error 4 :: Result Int ()) + Writer () 8 @= fmap twice (Writer () 4) + Writer 8 () @= mapW twice (Writer 4 ()) + Square () () 8 10 @= fmap twice (Square () () 4 5) + Square 8 10 () () @= mapFirst twice (Square 4 5 () ()) + [Twice (Left 8), Twice (Right 10)] @= (fmap . fmap) twice [Twice (Left 4), Twice (Right 5)] + Node 8 (Leaf 10) (Leaf 12) @= bimap twice twice (Node 4 (Leaf 5) (Leaf 6)) + (8 :< Just 10) @= bimap twice twice (4 :< Just 5) + [One 8, Two False, Three 1] @= fmap (mapThree twice not length) [One 4, Two True, Three [()]] + + let t1 = Right (Just [((), 4)]) + map1 twice t1 @= map1' twice t1 + + let t2 x = Left [x] :: Either [Int] () + map2 twice t2 4 @= map2' twice t2 4 + + let t3 = ([4], Left 5) + map3 twice t3 @= map3' twice t3 + + let t4 = ((), Just [Right 4]) + map4 twice t4 @= map4' twice t4 + map4 twice t4 @= map4'' twice t4 + + map6 (const True) twice t4 @= map6' (const True) twice t4 + + let t5 = [Left 4, Right (False, [()])] + fmap (map5 twice not length) t5 @= fmap (map5 twice not length) t5 + + -- Foldable + 0 @= foldTest Unit + 4 @= foldTest (Ok 4 :: Result () Int) + 0 @= foldTest (Error 4 :: Result Int Int) + 4 @= foldTest (Writer () 4) + 9 @= foldTest (Square () () 4 5) + 3 @= foldTest (Node 4 (Leaf 1) (Leaf 2) :: Tree Int Int) + + -- Traversable + Unit @= travTest Unit + Ok 0 @= travTest (Ok 4 :: Result () Int) + Error 4 @= travTest (Error 4 :: Result Int Int) + Writer () 0 @= travTest (Writer () 4) + Square () () 0 1 @= travTest (Square () () 4 5) + Node 4 (Leaf 0) (Leaf 1) @= travTest (Node 4 (Leaf 5) (Leaf 6) :: Tree Int Int) + +-- Assert equality +(@=) :: (Eq a, Show a) => a -> a -> IO () +(@=) x y | x == y = pure () + | otherwise = do + putStrLn "Not equal:" + print x + print y + exitFailure