Fixpoint zip {X} (f1 f2 : nat -> X) n :=
  match n with
  | O => f1 O
  | S O => f2 0
  | S (S n) => zip (fun n => f1 (S n)) (fun n => f2 (S n)) n
  end.

(* Specifications: *)
Lemma zip_ext {X} f1 f2 g1 g2 : (forall x, f1 x = g1 x) -> (forall x, f2 x = g2 x) -> forall k, @zip X f1 f2 k = @zip X g1 g2 k.
Lemma zip_1 {X} f1 f2 n : @zip X f1 f2 (2 * n) = f1 n.
Lemma zip_2 {X} f1 f2 n : @zip X f1 f2 (1 + 2 * n) = f2 n.
Lemma finite_union_intersection {X Y} (A1 A2 : X -> Prop) (P : Y -> X -> Prop) : finite (fun y => exists x, A1 x /\ P y x) -> finite (fun y => exists x, A2 x /\ P y x) -> finite (fun y => exists x, (A1 x \/ A2 x) /\ P y x).
Lemma finite_product: forall {A B} {PA : A -> Prop} {PB : B -> Prop}, finite PA -> finite PB -> finite (fun ab => PA (fst ab) /\ PB (snd ab)).
Lemma finite_nat_bound A : @finite nat A <-> exists b, forall a, A a -> a < b.
Lemma finite_union_intersection_nat {X} (A1 A2 : X -> Prop) (P : nat -> X -> Prop) : finite (fun n => exists x, A1 x /\ P n x) -> finite (fun n => exists x, A2 x /\ P n x) -> finite (fun n => exists x, (A1 x \/ A2 x) /\ P n x).
Lemma not_infinite_finite A : (forall P, ~~P -> P) -> ~ infinite A <-> finite A.
Lemma ramsey_inf_bin {X} (A1 A2 : X -> Prop) (P : nat -> X -> Prop) : (forall P, P \/ ~P) -> infinite (fun n => exists x, (A1 x \/ A2 x) /\ P n x) -> infinite (fun n => exists x, A1 x /\ P n x) \/ infinite (fun n => exists x, A2 x /\ P n x).
Lemma ramsey_inf {X} (A : X -> Prop) (P : nat -> X -> Prop) : (forall P, P \/ ~P) -> finite A -> infinite (fun n => exists x, A x /\ P n x) -> exists x, A x /\ infinite (fun n => P n x).