(* Autor(s): Andrej Dudenhefner (1) Yannick Forster (1) Affiliation(s): (1) Saarland University, Saarbrücken, Germany *)
(* evaluates propositional predicate P on all free variables *)
Fixpoint allfv_poly_type (p: nat -> Prop) (t: poly_type) :=
match t with
| poly_var x => p x
| poly_arr s t => allfv_poly_type p s /\ allfv_poly_type p t
| poly_abs t => allfv_poly_type (scons True p) t
end.
(* is_simple t holds iff t does not contain quantifications *)
Fixpoint is_simple (t: poly_type) :=
match t with
| poly_var _ => True
| poly_arr s t => is_simple s /\ is_simple t
| poly_abs _ => False
end.
(* COMPOUND poly_type CONSTRUCTION *)
(* many_poly_arr [s1 .. sn] t = s1 -> .. sn -> t *)
Definition many_poly_arr (arguments: list poly_type) (target: poly_type) :=
fold_right poly_arr target arguments.
(* many_poly_abs n t = ∀ .. ∀ t *)
Definition many_poly_abs (n: nat) (t: poly_type) :=
Nat.iter n poly_abs t.
Fact subst_poly_type_many_poly_abs {σ n target} :
subst_poly_type σ (many_poly_abs n target) =
many_poly_abs n (subst_poly_type (Nat.iter n up_poly_type_poly_type σ) target).
Fact ren_poly_type_many_poly_abs {ξ n target} :
ren_poly_type ξ (many_poly_abs n target) =
many_poly_abs n (ren_poly_type (Nat.iter n up_ren ξ) target).
Fact subst_poly_type_many_poly_arr {σ args target} :
subst_poly_type σ (many_poly_arr args target) =
many_poly_arr (map (subst_poly_type σ) args) (subst_poly_type σ target).
(* last_poly_var (∀..∀ s1 -> .. sn -> x) = Some x if x is free *)
Fixpoint last_poly_var (t: poly_type) : option nat :=
match t with
| poly_var x => Some x
| poly_arr _ t => last_poly_var t
| poly_abs t => if last_poly_var t is Some (S x) then Some x else None
end.
(* parameters s1 -> .. -> sn -> x = [s1; ..; sn] *)
Fixpoint parameters_poly_arr (t: poly_type) : list poly_type :=
match t with
| poly_var x => []
| poly_arr s t => s :: parameters_poly_arr t
| poly_abs t => []
end.
Fact up_ren_id {x} : up_ren id x = x.
(* reexport substitution extensionality lemma from syntax *)
Definition ext_poly_type := ext_poly_type.
Definition is_poly_abs (t: poly_type) := if t is poly_abs _ then True else False.
(* x does not occur in t *)
Definition fresh_in (x: nat) (t: poly_type) := allfv_poly_type (fun y => x <> y) t.
Fixpoint fresh_inb (x: nat) (t: poly_type) :=
match t with
| poly_var y => if PeanoNat.Nat.eq_dec x y then false else true
| poly_arr s t => fresh_inb x s && fresh_inb x t
| poly_abs t => fresh_inb (1+x) t
end.

Lemma fresh_in_many_poly_absI {x n t} : fresh_in (n+x) t -> fresh_in x (many_poly_abs n t).