(* * Copyright (c) 2009-2011, Andrew Appel, Robert Dockins and Aquinas Hobor. * *)
Set Implicit Arguments.
Module CovariantFunctor.
Record functorFacts (PS : Type -> Type)
(fmap : forall A B (f : A -> B), PS A -> PS B) : Type :=
FunctorFacts {
ff_id : forall A, fmap _ _ (id A) = id (PS A);
ff_comp : forall A B C (f : B -> C) (g : A -> B),
fmap _ _ f oo fmap _ _ g = fmap _ _ (f oo g)
}.
Record functor : Type := Functor {
_functor: Type -> Type;
fmap : forall A B (f : A -> B), _functor A -> _functor B;
functor_facts : functorFacts _functor fmap
}.
End CovariantFunctor.
Module ContraVariantFunctor.
Record functorFacts (PS : Type -> Type)
(fmap : forall A B (f : B -> A), PS A -> PS B) : Type :=
FunctorFacts {
ff_id : forall A, fmap _ _ (id A) = id (PS A);
ff_comp : forall A B C (f : C -> B) (g : B -> A),
fmap _ _ f oo fmap _ _ g = fmap _ _ (g oo f)
}.
Record functor : Type := Functor {
_functor: Type -> Type;
fmap : forall A B (f : B -> A), _functor A -> _functor B;
functor_facts : functorFacts _functor fmap
}.
End ContraVariantFunctor.
Module MixVariantFunctor.
Record functorFacts (PS : Type -> Type)
(fmap : forall A B (f1 : A -> B) (f2 : B -> A), PS A -> PS B) : Type :=
FunctorFacts {
ff_id : forall A, fmap _ _ (id A) (id A) = id (PS A);
ff_comp : forall A B C (f1 : B -> C) (f2 : C -> B) (g1 : A -> B)
(g2 : B -> A), fmap _ _ f1 f2 oo fmap _ _ g1 g2 = fmap _ _ (f1 oo g1) (g2 oo f2)
}.
Record functor : Type := Functor {
_functor: Type -> Type;
fmap : forall A B (f1 : A -> B) (f2 : B -> A), _functor A -> _functor B;
functor_facts : functorFacts _functor fmap
}.
End MixVariantFunctor.
Module CovariantBiFunctor.
Record functorFacts (PS : Type -> Type -> Type)
(fmap : forall A1 B1 A2 B2 (f1 : A1 -> B1) (f2 : A2 -> B2),
PS A1 A2 -> PS B1 B2) : Type :=
FunctorFacts {
ff_id : forall A1 A2, fmap _ _ _ _ (id A1) (id A2) = id (PS A1 A2);
ff_comp : forall A1 A2 B1 B2 C1 C2 (f1 : B1 -> C1) (f2 : B2 -> C2)
(g1 : A1 -> B1) (g2 : A2 -> B2),
fmap _ _ _ _ f1 f2 oo fmap _ _ _ _ g1 g2 = fmap _ _ _ _ (f1 oo g1) (f2 oo g2)
}.
Record functor : Type := Functor {
_functor: Type -> Type -> Type;
fmap : forall A1 B1 A2 B2 (f1 : A1 -> B1) (f2 : A2 -> B2),
_functor A1 A2 -> _functor B1 B2;
functor_facts : functorFacts _functor fmap
}.
End CovariantBiFunctor.
Module CoContraVariantBiFunctor.
Record functorFacts (PS : Type -> Type -> Type)
(fmap : forall A1 B1 A2 B2 (f1 : A1 -> B1) (f2 : B2 -> A2),
PS A1 A2 -> PS B1 B2) : Type :=
FunctorFacts {
ff_id : forall A1 A2, fmap _ _ _ _ (id A1) (id A2) = id (PS A1 A2);
ff_comp : forall A1 A2 B1 B2 C1 C2 (f1 : B1 -> C1) (f2 : C2 -> B2)
(g1 : A1 -> B1) (g2 : B2 -> A2),
fmap _ _ _ _ f1 f2 oo fmap _ _ _ _ g1 g2 = fmap _ _ _ _ (f1 oo g1) (g2 oo f2)
}.
Record functor : Type := Functor {
_functor: Type -> Type -> Type;
fmap : forall A1 B1 A2 B2 (f1 : A1 -> B1) (f2 : B2 -> A2),
_functor A1 A2 -> _functor B1 B2;
functor_facts : functorFacts _functor fmap
}.
End CoContraVariantBiFunctor.
Coercion CovariantFunctor._functor:
CovariantFunctor.functor >-> Funclass.
Coercion ContraVariantFunctor._functor:
ContraVariantFunctor.functor >-> Funclass.
Coercion MixVariantFunctor._functor:
MixVariantFunctor.functor >-> Funclass.
Coercion CovariantBiFunctor._functor:
CovariantBiFunctor.functor >-> Funclass.
Coercion CoContraVariantBiFunctor._functor:
CoContraVariantBiFunctor.functor >-> Funclass.
Module CovariantFunctorLemmas.

Lemma fmap_id {F: functor} : forall A, fmap F (id A) = id (F A).
Definition fchoice (F1 F2: functor): functor :=
GeneralFunctorGenerator.CovariantBiFunctor_CovariantFunctor_compose
CovariantBiFunctorGenerator.Fchoice
F1
F2.