Ltac find_in_list A L :=
match L with
| A :: _ => constr:(O)
| _ :: ?Y => let n := find_in_list A Y in constr:(S n)
| nil => fail
end.
Ltac length_of R :=
match R with
|  nil => constr:(O)
|  _:: ?R1 => let n := length_of R1 in constr:(S n)
end.
Fixpoint insert {A} (n: nat) (x: A) (ys: list A) {struct n} : list A :=
match n with
| O => x::ys
| S n' => match ys with nil => x::ys | y::ys' => y::insert n' x ys' end
end.
(* Note: in the grab_indexes function, it's important that the {struct} induction NOT be on xs, because that list might not be concrete all the way to the end, where the ns list will be concrete. Thus we do it this particular way.  *)
Fixpoint  grab_indexes' {A} (ns: list (option nat)) (xs: list A) {struct ns} : list A * list A :=
match ns, xs with
| nil, xs => (nil, xs)
| _, nil => (nil,nil)
| Some n::ns', x::xs' => let (al,bl) := grab_indexes' ns' xs'
in (insert n x al, bl)
| None :: ns', x::xs' => let (al,bl) := grab_indexes' ns' xs'
in (al, x::bl)
end.
Fixpoint grab_calc' (k: Z) (z: nat) (ns: list (option nat)): list (option nat) :=
match z, ns with
| O, _::ns' => Some (nat_of_Z k) :: ns'
| S z', None::ns' => None :: grab_calc' k z' ns'
| S z', Some n :: ns => Some n :: grab_calc' (k-1) z' ns
| O, nil => Some O :: nil
| S z', nil => None :: grab_calc' k z' nil
end.
Fixpoint grab_calc (k: Z) (zs: list Z) (ns: list (option nat)) : list (option nat) :=
match zs with
| nil => ns
| z::zs' => grab_calc (k+1) zs' (grab_calc' k (nat_of_Z z) ns)
end.
(* Eval compute in grab_calc 0 (3::1::5::nil) nil. *)
(* Define app_alt, just like app, so we have better control over which things get unfolded *)
Definition app_alt {A: Type} :=
fix app (l m : list A) : list A :=
match l with
| nil => m
| a :: l1 => a :: app l1 m
end.
Definition grab_indexes {A} (ns: list Z) (xs: list A) : list A :=
let (al,bl) := grab_indexes' (grab_calc 0 ns nil) xs in app_alt al bl.
(* TESTING Variables (a b c d e f g h i j : assert). Eval compute in grab_indexes (1::4::6::nil) (a::b::c::d::e::f::g::h::i::j::nil). Eval compute in grab_indexes (1::6::4::nil) (a::b::c::d::e::f::g::h::i::j::nil). *)

(* Specifications: *)
Lemma fold_right_nil: forall {A B} (f: A -> B -> B) (z: B),
fold_right f z nil = z.
Lemma fold_right_sepcon_app :
forall P Q, fold_right_sepcon (P++Q) =
fold_right_sepcon P * fold_right_sepcon Q.
Lemma grab_indexes_SEP :
forall (ns: list Z) xs, SEPx xs = SEPx (grab_indexes ns xs).