(* * Basic definitions of decidablility and Functions - includes basic Lemmas about said functions *)
From Undecidability.Shared.Libs.PSL Require Export Base.
(* * Definition of useful tactics *)
(* dec is used to destruct all decisions appearing in the goal or assumptions. *)
Ltac dec := repeat (destruct Dec).
(* This tactic completely solves listComplete goals for base types *)
Ltac listComplete := intros x; simpl; dec; destruct x; try congruence.
(* simplifies (decision x = x) *)
Ltac deq x := destruct (Dec (x=x)) as [[]  | isnotequal]; [> | contradict isnotequal; reflexivity] .
(* Function that takes two lists and returns the list of all pairs of elements from the two lists *)
Fixpoint prodLists {X Y: Type} (A: list X) (B: list Y) {struct A} :=
match A with
| nil => nil
| cons x A' => map (fun y => (x,y)) B ++ prodLists A' B end.
(* This function takes a (A: list X) and yields a list (option X) which for every x in A contains Some x. The resultung list also contains None. The order is preserved. None is the first element of the resulting list. *)
Definition toOptionList {X: Type} (A: list X) :=
None :: map (@Some _) A .
(* This function counts the number of occurences of an element in a given list and returns the result *)
Fixpoint count (X: Type) `{eq_dec X}  (A: list  X) (x:  X) {struct A} : nat :=
match A with
| nil => O
| cons y A' =>  if Dec (x=y) then S(count A' x) else count A' x end.
Definition toSumList1 {X: Type}  (Y: Type) (A: list X): list (X + Y) :=
map inl A.
Definition toSumList2 {Y: Type}  (X: Type) (A: list Y): list (X + Y) :=
map inr A.
(* * Basic lemmas about functions *)
(* In the list containing all pairs of (x,y') with y' from a list B the pair (x,y) is contained exactly as many times as y is contained in the list B. *)
(* If a list is split somewhere in two list the number of occurences of an element in the list is equal to the sum of the number of occurences in the left and the right part. *)
(* * Various helpful Lemmas *)

(* If the concatenation of two lists is nil then each list was nil *)
Lemma appendNil (X: Type) (A B: list X) :
A ++ B = nil -> A = nil /\ B = nil.