(** * Finite types *)
(* [fin n : Type] is a type with [n] inhabitants. It is isomorphic to [Coq.Vector.Fin.t] from the standard library, but we found this formulation easier to reason about. *)
(* In this compiler, we use [fin n] as the type of "block labels" in [Asm] programs (program locations that can be jumped to). In an earlier version, labels could be any type, but this restriction makes [Asm] programs easier to introspect for defining optimizations (though the current development doesn't make use of it). *)
(* The instances at the end derive categorical operations for the subcategories of [Fun] and [ktree] on finite types (instead of arbitrary types). *)
(* begin hide *)
Arith
Lia.
ITree
ITreeFacts
Basics.Category
Basics.CategorySub.
(* end hide *)
(* Type with [n] inhabitants. *)
Definition fin (n : nat) : Type := { x : nat | x < n }.
(* Hide proof terms. *)
(* N.B.: [x < n] unfolds to [S x < n], which is why we don't make the first field more precise. *)
Notation fi' i := (exist (fun j : nat => _) i _).
Program Definition f0 {n} : fin (S n) := fi' 0.
Next Obligation. lia. Defined.
Program Definition fS {n} : fin n -> fin (S n) :=
fun i => fi' (S (proj1_sig i)).
Next Obligation.
destruct i; simpl; lia.
Defined.
Instance FinInitial {E} : Initial (sub (ktree E) fin) 0 := fun _ => fin_0.
Definition merge_fin_sum (n m: nat) : fin n + fin m -> fin (n + m) :=
fun v =>
match v with
| inl v => L m v
| inr v => R n v
end.

Lemma merge_split:
forall (n m : nat) (a : fin (n + m)), merge_fin_sum n m (split_fin_sum n m a) = a.