Set Universe Polymorphism.
Set Primitive Projections.
Section plist.
Polymorphic Universe i.
Variable T : Type@{i}.
Polymorphic Inductive plist : Type@{i} :=
| pnil
| pcons : T -> plist -> plist.
Polymorphic Fixpoint length (ls : plist) : nat :=
match ls with
| pnil => 0
| pcons _ ls' => S (length ls')
end.
Polymorphic Fixpoint app (ls ls' : plist) : plist :=
match ls with
| pnil => ls'
| pcons l ls => pcons l (app ls ls')
end.
Polymorphic Definition hd (ls : plist) : poption T :=
match ls with
| pnil => pNone
| pcons x _ => pSome x
end.
Polymorphic Definition tl (ls : plist) : plist :=
match ls with
| pnil => ls
| pcons _ ls => ls
end.
Polymorphic Fixpoint pIn (a : T) (l : plist) : Prop :=
match l with
| pnil => False
| pcons b m => b = a \/ pIn a m
end.
Polymorphic Inductive pNoDup : plist -> Prop :=
pNoDup_nil : pNoDup pnil
| pNoDup_cons : forall (x : T) (l : plist),
~ pIn x l -> pNoDup l -> pNoDup (pcons x l).
Polymorphic Fixpoint inb {RelDecA : RelDec (@eq T)} (x : T) (lst : plist) :=
match lst with
| pnil => false
| pcons l ls => if x ?[ eq ] l then true else inb x ls
end.
Polymorphic Fixpoint anyb (p : T -> bool) (ls : plist) : bool :=
match ls with
| pnil => false
| pcons l ls0 => if p l then true else anyb p ls0
end.
Polymorphic Fixpoint allb (p : T -> bool) (lst : plist) : bool :=
match lst with
| pnil => true
| pcons l ls => if p l then allb p ls else false
end.
Polymorphic Fixpoint nodup {RelDecA : RelDec (@eq T)} (lst : plist) :=
match lst with
| pnil => true
| pcons l ls => andb (negb (inb l ls)) (nodup ls)
end.
Polymorphic Fixpoint nth_error (ls : plist) (n : nat) : poption T :=
match n , ls with
| 0 , pcons l _ => pSome l
| S n , pcons _ ls => nth_error ls n
| _ , _ => pNone
end.
Section folds.
Polymorphic Universe j.
Context {U : Type@{j}}.
Variable f : T -> U -> U.
Polymorphic Fixpoint fold_left (acc : U) (ls : plist) : U :=
match ls with
| pnil => acc
| pcons l ls => fold_left (f l acc) ls
end.
Polymorphic Fixpoint fold_right (ls : plist) (rr : U) : U :=
match ls with
| pnil => rr
| pcons l ls => f l (fold_right ls rr)
end.
End folds.
End plist.
Arguments pnil {_}.
Arguments pcons {_} _ _.
Arguments app {_} _ _.
Arguments pIn {_} _ _.
Arguments pNoDup {_} _.
Arguments anyb {_} _ _.
Arguments allb {_} _ _.
Arguments inb {_ _} _ _.
Arguments nodup {_ _} _.
Arguments fold_left {_ _} _ _ _.
Arguments fold_right {_ _} _ _ _.
Arguments nth_error {_} _ _.
Section plistFun.
Polymorphic Fixpoint split {A B : Type} (lst : plist (pprod A B)) :=
match lst with
| pnil => (pnil, pnil)
| pcons (ppair x y) tl => let (left, right) := split tl in (pcons x left, pcons y right)
end.

(* Specifications: *)
Lemma pIn_split_l {A B : Type} (lst : plist (pprod A B)) (p : pprod A B) (H : pIn p lst) :
(pIn (pfst p) (fst (split lst))).
Lemma pIn_split_r {A B : Type} (lst : plist (pprod A B)) (p : pprod A B) (H : pIn p lst) :
(pIn (psnd p) (snd (split lst))).
Lemma pIn_app_iff (A : Type) (l l' : plist A) (a : A) :
pIn a (app l l') <-> pIn a l \/ pIn a l'.