Ltac extract_exists_in_SEP' PQR :=
match PQR with
| PROPx ?P (LOCALx ?Q (SEPx (?R))) =>
match R with context [(@exp _ _ ?A ?S) :: ?R'] =>
let n := constr:((length R - Datatypes.S (length R'))%nat) in
let n' := eval lazy beta zeta iota delta in n in
rewrite (@extract_nth_exists_in_SEP n' P Q R A S (eq_refl _));
unfold replace_nth at 1;
rewrite ?exp_andp2
end
end.
Ltac extract_exists_from_SEP :=
match goal with
| |- semax _ ?Pre _ _ =>
extract_exists_in_SEP' Pre; apply extract_exists_pre
| |- _ && ?Pre |-- ?Post =>
let P := fresh "POST" in set (P := Post);
extract_exists_in_SEP' Pre; subst P; apply exp_left
| |- ?Pre |-- ?Post => (* this case is obsolete, should probably be deleted *)
let P := fresh "POST" in set (P := Post);
extract_exists_in_SEP' Pre; subst P; apply exp_left
end.
Ltac move_from_SEP' PQR :=
match PQR with
| PROPx ?P (LOCALx ?Q (SEPx (?R))) =>
match R with context [(prop ?P1 && ?S) :: ?R'] =>
let n := constr:((length R - Datatypes.S (length R'))%nat) in
let n' := eval lazy beta zeta iota delta in n in
rewrite(@extract_prop_in_SEP n' P1 S P Q R (eq_refl _));
unfold replace_nth at 1
end
end.

Lemma derives_extract_PROP' :
forall (P1: Prop) P QR S,
(P1 -> PROPx P QR |-- S) ->
PROPx (P1::P) QR |-- S.