Section PartialFun.
(* A partial function is a function from X -> option Y where X equality of members of type X is decidable. *)
Context {X Y : Type}.
Context {RelDec_X : RelDec (@eq X)}.
Context {RDC : RelDec_Correct RelDec_X}.
Definition pfun := X -> option Y.
Definition pfun_eq (f1 f2 : pfun) := forall s, (f1 s) = (f2 s).
Global Instance EquivalencePfun : Equivalence pfun_eq.
Definition emptyFun : pfun := fun _ => None.
Definition pfun_update (f : pfun) (x : X) (y : Y) :=
fun z => if x ?[ eq ] z then Some y else f z.
Definition pfun_in (f : pfun) (x : X) : Prop := exists y, f x = Some y.
Ltac SepOpSolve :=
match goal with
| H : (match ?f ?x with | Some _ => _ | None => _ end) |- _ =>
let e := fresh "e" in let y := fresh "y" in remember (f x) as e;
destruct e as [y |]; SepOpSolve
| H : _ \/ _ |- _ => destruct H as [H | H]; SepOpSolve
| H : _ /\ _ |- _ => let H1 := fresh "H" in destruct H as [H H1]; SepOpSolve
| H : ?f ?x = _ |- context [match ?f ?x with | Some _ => _ | None => _ end] =>
rewrite H; SepOpSolve
| H : forall x : X, _ |- _ =>
match goal with
| x : X |- _ => specialize (H x)
end; SepOpSolve
| _ => subst; try intuition congruence
end.
(* We can create a separation algebra for partial functions with the following definitions for sa_unit and sa_mul *)
Global Instance PFunSepAlgOps : SepAlgOps (X -> option Y) := {
sa_unit f := pfun_eq f emptyFun;
sa_mul    := fun a b c => forall x,
match c x with
| Some y => (a x = Some y /\ b x = None) \/
(b x = Some y /\ a x = None)
| None => a x = None /\ b x = None
end
}.
(* Proving that partial functions actually form a separation algebra is straightforward modulo some LTac magic. *)
Global Instance PFunSepAlg : SepAlg (rel := pfun_eq) (X -> option Y).

Lemma pfun_in_sa_mulR (a b c : X -> option Y) (x : X) (H : sa_mul a b c) (Hin : pfun_in c x) : pfun_in a x \/ pfun_in b x.