Section MapFoldDef.
Variable M : Type.
Variable neutral : M.
Variable op : M -> M -> M.
Fixpoint MapFold1 (f:ad -> A -> M) (pf:ad -> ad)
(m:Map A) {struct m} : M :=
match m with
| M0 => neutral
| M1 a y => f (pf a) y
| M2 m1 m2 =>
op (MapFold1 f (fun a0:ad => pf (N.double a0)) m1)
(MapFold1 f (fun a0:ad => pf (Ndouble_plus_one a0)) m2)
end.
Definition MapFold (f:ad -> A -> M) (m:Map A) :=
MapFold1 f (fun a:ad => a) m.
Variable State : Type.
Variable f : State -> ad -> A -> State * M.
Fixpoint MapFold1_state (state:State) (pf:ad -> ad)
(m:Map A) {struct m} : State * M :=
match m with
| M0 => (state, neutral)
| M1 a y => f state (pf a) y
| M2 m1 m2 =>
match MapFold1_state state (fun a0:ad => pf (N.double a0)) m1 with
| (state1, x1) =>
match
MapFold1_state state1
(fun a0:ad => pf (Ndouble_plus_one a0)) m2
with
| (state2, x2) => (state2, op x1 x2)
end
end
end.
Definition MapFold_state (state:State) :=
MapFold1_state state (fun a:ad => a).
End MapFoldDef.
Definition alist := list (ad * A).
Definition anil := nil (A:=(ad * A)).
Definition acons := cons (A:=(ad * A)).
Definition aapp := app (A:=(ad * A)).
Definition alist_of_Map :=
MapFold alist anil aapp (fun (a:ad) (y:A) => acons (a, y) anil).
Fixpoint alist_semantics (l:alist) : ad -> option A :=
match l with
| nil => fun _:ad => None
| (a, y) :: l' =>
fun a0:ad => if N.eqb a a0 then Some y else alist_semantics l' a0
end.
Definition ad_inj (pf:ad -> ad) :=
forall a0 a1:ad, pf a0 = pf a1 -> a0 = a1.
Fixpoint Map_of_alist (l:alist) : Map A :=
match l with
| nil => M0 A
| (a, y) :: l' => MapPut A (Map_of_alist l') a y
end.

Lemma MapFold_as_fold :
forall (M:Type) (neutral:M) (op:M -> M -> M),
(forall a b c:M, op (op a b) c = op a (op b c)) ->
(forall a:M, op neutral a = a) ->
(forall a:M, op a neutral = a) ->
forall (f:ad -> A -> M) (m:Map A),
MapFold M neutral op f m =
fold_right (fun (r:ad * A) (m:M) => let (a, y) := r in op (f a y) m)
neutral (alist_of_Map m).