Set Implicit Arguments.
Set Strict Implicit.
Section keyed.
Variable K : Type.
Variable R : K -> K -> Prop.
Variable RD_K : RelDec R.
Variable V : Type.
Definition alist : Type := list (K * V).
Definition alist_remove (k : K) (m : alist) : alist :=
List.filter (fun x => negb (k ?[ R ] (fst x))) m.
Definition alist_add (k : K) (v : V) (m : alist) : alist :=
(k, v) :: alist_remove k m.
Fixpoint alist_find (k : K) (m : alist) : option V :=
match m with
| nil => None
| (k',v) :: ms =>
if k ?[ R ] k' then
Some v
else
alist_find k ms
end.
Section fold.
Local Open Scope monad_scope.
Variables T : Type.
Variable f : K -> V -> T -> T.
Fixpoint fold_alist (acc : T) (map : alist) : T :=
match map with
| nil => acc
| (k,v) :: m =>
let acc := f k v acc in
fold_alist acc m
end.
End fold.
Definition alist_union (m1 m2 : alist) : alist :=
fold_alist alist_add m2 m1.
Global Instance Map_alist : Map K V alist :=
{ empty  := nil
; add    := @alist_add
; remove := alist_remove
; lookup := alist_find
; union  := @alist_union
}.
Section proofs.
Hypothesis RDC_K : RelDec_Correct RD_K.
Hypothesis Refl : Reflexive R.
Hypothesis Sym : Symmetric R.
Hypothesis Trans : Transitive R.
Definition mapsto_alist (m : alist) k v : Prop :=
alist_find k m = Some v.

Lemma mapsto_alist_cons : forall k v m k' v',
mapsto_alist ((k',v') :: m) k v <->
(   (mapsto_alist m k v /\ ~R k k')
\/ (R k k' /\ v = v')).