(* The shape of a tree can be expressed by mapping (fun _ => tt) over it. *)
Fixpoint map {A B} (f : A -> B) (t : tree A) : tree B :=
  match t with
  | atom a => atom (f a)
  | node l => node (List.map (map f) l)
  end.Definition shape {A} (t : tree A) : tree unit :=
  map (fun _ => tt) t.Fixpoint tree_map' {A B} (f : A -> B) (t : tree A) : tree B :=
  let fix tree_map_loop {A B} (f : A -> B) (l : list (tree A)) acc :=
      match l with
      | [] => rev_rec acc []
      | a :: l => tree_map_loop f l (map f a :: acc)
      end in
  match t with
  | atom a => atom (f a)
  | node l => node (tree_map_loop f l [])
  end.Definition tree_map_loop :=
  fix tree_map_loop {A B} (f : A -> B) (l : list (tree A)) acc :=
    match l with
    | [] => rev_rec acc []
    | a :: l => tree_map_loop f l (map f a :: acc)
    end.

(* Specifications: *)
Lemma tree_map_loop_spec : forall {A B} (f : A -> B) l acc, tree_map_loop f l acc = rev acc ++ List.map (map f) l.
Theorem tree_map'_spec : forall {A B} (f : A -> B) (t : tree A), tree_map' f t = map f t.