Set Implicit Arguments.
(* Most user-defined datatypes are tree-like, which are typically nontrivial to deserialize by structural recursion on the bitstream. This file provides a generic multi-arity tree type and its serializer/deserializer. Other tree-like types can be serialized by first converting to a tree and then serializing. *)
Section tree.
(* The tree is parametrized on the type of data stored at the leaves. *)
Variable A : Type.
(* Each node of the tree contains a list of subtrees. Coq does not generate a useful induction scheme for such types, so we just tell it not to generate anything, and we'll write our own. *)
Local Unset Elimination Schemes.
Inductive tree : Type :=
| atom : A -> tree
| node : list tree -> tree
.
(* Here is an actually useful recursion principle for tree, which requires an additional motive P_list. *)
Section tree_rect.
Variable P : tree -> Type.
Variable P_list : list tree -> Type.
Hypothesis P_nil : P_list [].
Hypothesis P_cons : forall t l, P t -> P_list l -> P_list (t :: l).
Hypothesis P_atom : forall a, P (atom a).
Hypothesis P_node : forall l, P_list l -> P (node l).
Fixpoint tree_rect (t : tree) : P t :=
let fix go_list (l : list tree) : P_list l :=
match l with
| [] => P_nil
| t :: l => P_cons (tree_rect t) (go_list l)
end
in
match t with
| atom a => P_atom a
| node l => P_node (go_list l)
end.
End tree_rect.
(* Setting P_list := List.Forall P is a reasonable default. *)
Section tree_ind.
Variable P : tree -> Prop.
Hypothesis P_atom : forall a, P (atom a).
Hypothesis P_node : forall l, List.Forall P l -> P (node l).
Definition tree_ind (t : tree) : P t :=
tree_rect P (List.Forall P)
(List.Forall_nil _)
(fun t l Pt Pl => List.Forall_cons _ Pt Pl) P_atom P_node t.
End tree_ind.
End tree.
Fixpoint rev_rec {A} (l : list A) (acc : list A) :=
match l with
| [] => acc
| a :: l => rev_rec l (a :: acc)
end.

(* Specifications: *)
Lemma rev_rec_spec : forall {A : Type} (l : list A) acc,
rev_rec l acc = rev l ++ acc.