Disclaimer: I fear this post got quite long, however, I feel that in a smaller setup some valuable background information would be lost.
I am currently trying to change my formalisation to use the locally nameless representation by Charguéraud et al [1]. Apparently, this adaption is not as straightforward as I hoped because my definition of expressions contains lists (at least I currently think this is the main problem).
So, I have the following (minimal) definition of expressions.
Require Import Coq.Lists.List.
Require Import Coq.Arith.PeanoNat.
Parameter atom : Set.
Parameter eq_atom_dec : forall x y : atom, {x = y} + {x <> y}.
Definition VarIndex := nat.
Inductive Expr : Type :=
| BVar : VarIndex -> VarIndex -> Expr
| FVar : atom -> Expr
| LetB : list Expr -> Expr -> Expr.
With this definition at hand I can define the opening operation.
Fixpoint open_rec (k: VarIndex) (u: list Expr) (e: Expr) :=
match e with
| BVar i j => if Nat.eq_dec k i then List.nth j u e else e
| FVar x => e
| LetB es e' => LetB (List.map (open_rec (S k) u) es) (open_rec (S k) u e')
end.
Notation "{ k ~> u } t" := (open_rec k u t) (at level 67).
Definition open e u := open_rec 0 u e.
So far so good. Next the property of being "locally closed" is defined inductively as follows.
Inductive lc : Expr -> Prop :=
| lc_var : forall x,
lc (FVar x)
| lc_let : forall (ts: list Expr) es e,
Forall lc es ->
lc (open e ts) ->
lc (LetB es e).
The tutorial now states that we can proof a lemma about the interaction of lc
and open
, i.e. in a locally closed expressions nothing happens when we substitute a variable.
(* this is a auxiliary lemma that works just fine for me *)
Lemma open_rec_lc_core : forall e (j: VarIndex) v (i: VarIndex) u,
i <> j ->
{j ~> v} e = {i ~> u} ({j ~> v} e) ->
e = {i ~> u} e.
Proof.
Admitted.
Lemma open_rec_lc0 : forall k u e,
lc e ->
e = {k ~> u} e.
Proof.
intros k u e LC.
generalize dependent k.
induction LC; intro k.
- reflexivity.
- simpl.
f_equal.
+ admit.
+ eapply open_rec_lc_core with (j := 0).
* auto.
* eapply IHLC.
Admitted.
As you can see, there is a case that is "admitted" in the proof. The problem here is that I have to proof something about the let-bindings, but everything I have at hand is the following:
H : Forall lc (map (fun e' : Expr => open e' ts) es)
LC : lc (open e ts)
IHLC : forall k : VarIndex, open e ts = {k ~> u} open e ts
What I need is an equivalent hypothesis to IHLC but for es
.
My first guess was that I need to modify the induction principle as it is usually done[2] for inductive definitions with lists as arguments.
However, I cannot workout a definition that actually type checks.
Fail Definition lc_ind2 :=
fun (P : Expr -> Prop) (f : forall x : atom, P (FVar x))
(f0 : forall (ts es : list Expr) (e : Expr),
Forall lc (map (fun e' : Expr => open e' ts) es) ->
lc (open e ts) -> P (open e ts) ->
Forall P (map (fun e' => open e' ts ) es) ->
P (LetB es e)) =>
fix F (e : Expr) (l : lc e) {struct l} : P e :=
match l in (lc e0) return (P e0) with
| lc_var x => f x
| lc_let ts es e0 f1 l0 =>
f0 ts es e0 f1 l0 (F (open e0 ts) l0)
((fix F' (es: list Expr) : Forall P es :=
match es with
| nil => Forall_nil P
| cons x xs => Forall_cons x (F x _) (F' xs)
end) (map (fun e' => open e' ts) es))
end.
Instead of _
in the application of Forall_cons
I need something of type lc x
, but I do not know how to come up with this value.
So, in the end my question is, if someone has an idea which definitions I need to modify in order to work with the LNR.
[1] Tutorial on LNR
[2] Induction principles with list arguments