Definition unmap_left (f:A -> B) :=
    forall x' y z,
      join x' (f y) (f z) ->
      { x:A & { y0:A | join x y0 z /\ f x = x' /\ f y0 = f y }}.Definition unmap_right (f:A -> B) :=
    forall x y z',
      join (f x) (f y) z' ->
      { y0: A & { z:A | join x y0 z /\ f y0 = f y /\ f z = z' }}.(*
Implicit Arguments unmap_right.
Implicit Arguments unmap_left.
*)

(*
Definition Join_paf (F: functor): Type :=
  forall A, Join (F A).
Definition Perm_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Perm_alg (F A).
Definition Sep_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Sep_alg (F A).
Definition Canc_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Canc_alg (F A).
Definition Disj_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Disj_alg (F A).
*)

(* TODO: change pafunctor, unmap_left, unmap_right into prop *)
Record pafunctor (F: functor) (paf_join: forall A, Join (F A)): Type := Pafunctor
{
  paf_join_hom : forall A B (f : A -> B) (g: B -> A), join_hom (fmap F f g);
  paf_preserves_unmap_left : forall A B (f : A -> B) (g: B -> A),
    unmap_left (paf_join A) (paf_join B) (fmap F f g);
  paf_preserves_unmap_right : forall A B (f : A -> B) (g: B -> A),
    unmap_right (paf_join A) (paf_join B) (fmap F f g)
}.(*
Implicit Arguments unmap_right.
Implicit Arguments unmap_left.
*)

(*
Definition Join_paf (F: functor): Type :=
  forall A, Join (F A).
Definition Perm_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Perm_alg (F A).
Definition Sep_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Sep_alg (F A).
Definition Canc_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Canc_alg (F A).
Definition Disj_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Disj_alg (F A).
*)

(* TODO: change pafunctor, unmap_left, unmap_right into prop *)
Record pafunctor (F: functor) (paf_join: forall A, Join (F A)): Type := Pafunctor
{
  paf_join_hom : forall A B (f : A -> B) (g: B -> A), join_hom (fmap F f g);
  paf_preserves_unmap_left : forall A B (f : A -> B) (g: B -> A),
    unmap_left (paf_join A) (paf_join B) (fmap F f g);
  paf_preserves_unmap_right : forall A B (f : A -> B) (g: B -> A),
    unmap_right (paf_join A) (paf_join B) (fmap F f g)
}.(*
Implicit Arguments unmap_right.
Implicit Arguments unmap_left.
*)

(*
Definition Join_paf (F: functor): Type :=
  forall A, Join (F A).
Definition Perm_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Perm_alg (F A).
Definition Sep_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Sep_alg (F A).
Definition Canc_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Canc_alg (F A).
Definition Disj_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Disj_alg (F A).
*)

(* TODO: change pafunctor, unmap_left, unmap_right into prop *)
Record pafunctor (F: functor) (paf_join: forall A, Join (F A)): Type := Pafunctor
{
  paf_join_hom : forall A B (f : A -> B) (g: B -> A), join_hom (fmap F f g);
  paf_preserves_unmap_left : forall A B (f : A -> B) (g: B -> A),
    unmap_left (paf_join A) (paf_join B) (fmap F f g);
  paf_preserves_unmap_right : forall A B (f : A -> B) (g: B -> A),
    unmap_right (paf_join A) (paf_join B) (fmap F f g)
}.(*
Implicit Arguments unmap_right.
Implicit Arguments unmap_left.
*)

(*
Definition Join_paf (F: functor): Type :=
  forall A, Join (F A).
Definition Perm_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Perm_alg (F A).
Definition Sep_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Sep_alg (F A).
Definition Canc_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Canc_alg (F A).
Definition Disj_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Disj_alg (F A).
*)

(* TODO: change pafunctor, unmap_left, unmap_right into prop *)
Record pafunctor (F: functor) (paf_join: forall A, Join (F A)): Type := Pafunctor
{
  paf_join_hom : forall A B (f : A -> B) (g: B -> A), join_hom (fmap F f g);
  paf_preserves_unmap_left : forall A B (f : A -> B) (g: B -> A),
    unmap_left (paf_join A) (paf_join B) (fmap F f g);
  paf_preserves_unmap_right : forall A B (f : A -> B) (g: B -> A),
    unmap_right (paf_join A) (paf_join B) (fmap F f g)
}.(*
Implicit Arguments unmap_right.
Implicit Arguments unmap_left.
*)

(*
Definition Join_paf (F: functor): Type :=
  forall A, Join (F A).
Definition Perm_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Perm_alg (F A).
Definition Sep_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Sep_alg (F A).
Definition Canc_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Canc_alg (F A).
Definition Disj_paf {F: functor} (paf_join: forall A, Join (F A)): Type :=
  forall A: Type, Disj_alg (F A).
*)

(* TODO: change pafunctor, unmap_left, unmap_right into prop *)
Record pafunctor (F: functor) (paf_join: forall A, Join (F A)): Type := Pafunctor
{
  paf_join_hom : forall A B (f : A -> B) (g: B -> A), join_hom (fmap F f g);
  paf_preserves_unmap_left : forall A B (f : A -> B) (g: B -> A),
    unmap_left (paf_join A) (paf_join B) (fmap F f g);
  paf_preserves_unmap_right : forall A B (f : A -> B) (g: B -> A),
    unmap_right (paf_join A) (paf_join B) (fmap F f g)
}.

(* Specifications: *)
Lemma paf_const : pafunctor (fconst T) (fun _ => J_T).
Lemma paf_equiv : @pafunctor F (fun A => @Join_equiv (F A)).
Lemma paf_pair : @pafunctor (fpair F1 F2) (fun A : Type => Join_prod (F1 A) (J_F1 A) (F2 A) (J_F2 A)).