Set Implicit Arguments.
(* Application to values & terms. *)
Inductive my_term :=
| MyTValue: my_value -> my_term
| MyTApp: my_term -> my_term -> my_term
with my_value :=
| MyVVar: nat -> my_value
| MyVAbs: my_term -> my_value.
Instance Var_my_value : Var my_value := {
var := MyVVar
}.
Fixpoint traverse_my_term (f : nat -> nat -> my_value) l t :=
match t with
| MyTValue v =>
MyTValue (traverse_my_value f l v)
| MyTApp t1 t2 =>
MyTApp (traverse_my_term f l t1) (traverse_my_term f l t2)
end
with traverse_my_value f l v :=
match v with
| MyVVar x =>
f l x
| MyVAbs t =>
MyVAbs (traverse_my_term f (1 + l) t)
end.
Instance Traverse_my_value_my_value : Traverse my_value my_value := {
traverse := traverse_my_value
}.
Instance Traverse_my_value_my_term : Traverse my_value my_term := {
traverse := traverse_my_term
}.
(* TEMPORARY It is unfortunate that we have to first prove two mutually dependent lemmas using [Lemma ... with ...], then write down two independent [Instance] declarations. I would prefer to be able to directly write two mutually depdendent instance declarations, using [Instance ... with ...]. Here, I am forced to duplicate the statement of the properties of interest, which is unpleasant. *)
Instance TraverseVarInjective_my_value_my_value :
@TraverseVarInjective my_value _ my_value _.
Instance TraverseVarInjective_my_value_my_term :
@TraverseVarInjective my_value _ my_term _.
Instance TraverseFunctorial_my_value_my_value : @TraverseFunctorial my_value _ my_value _.
Instance TraverseRelative_my_value_my_value : @TraverseRelative my_value my_value _.
Instance TraverseRelative_my_value_my_term : @TraverseRelative my_value my_term _.

Lemma traverse_my_value_var_is_identity:
forall f,
(forall l x, f l x = var x) ->
forall (t : my_value) l,
traverse f l t = t
with traverse_my_term_var_is_identity:
forall f,
(forall l x, f l x = var x) ->
forall (t : my_term) l,
traverse f l t = t.