【发布时间】:2016-10-11 11:41:12
【问题描述】:
免责声明:我担心这篇文章会很长,但是,我觉得在较小的设置中会丢失一些有价值的背景信息。
我目前正在尝试更改我的形式化以使用 Charguéraud 等人 [1] 的本地无名表示。显然,这种改编并不像我希望的那样简单,因为我对表达式的定义包含列表(至少我目前认为这是主要问题)。
所以,我有以下(最小的)表达式定义。
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.
有了这个定义,我就可以定义打开操作了。
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.
到目前为止一切顺利。接下来,“局部封闭”的属性归纳定义如下。
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).
本教程现在指出,我们可以证明lc 和open 的交互作用的引理,即在局部封闭表达式中,当我们替换变量时不会发生任何事情。
(* 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.
如您所见,证明中有一个案例被“承认”。这里的问题是我必须证明一些关于 let-bindings 的事情,但我手头的一切如下:
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
我需要的是与 IHLC 等效的假设,但对于 es。
我的第一个猜测是,我需要修改归纳原则,因为它通常用于 [2] 以列表作为参数的归纳定义。
但是,我无法确定实际类型检查的定义。
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.
在Forall_cons 的应用程序中,我需要lc x 类型的东西,而不是_,但我不知道如何得出这个值。
所以,最后我的问题是,如果有人知道我需要修改哪些定义才能使用 LNR。
[1]Tutorial on LNR
[2]Induction principles with list arguments
【问题讨论】:
-
什么是
VarIndex? -
哦,抱歉,这只是
nat的重命名,但感谢您发现这一点,我编辑了帖子。 -
(1) 为什么
BVar有2 个索引?它们的非正式含义是什么? (2)LetB非正式地代表什么? -
(1) 是 (2) 的结果。
LetB代表多个 let-bindings à la "let x = 31; y = x + 2" 并且BVar i j有两个索引来准确处理这些绑定器。i表示您必须通过多少个绑定器才能到达您的声明,如果是 let-binder,j表示要采用这些多绑定器中的哪一个(例如,1表示 x 和2表示上述 let 表达式中的 y)。 Charguéraud 在第 7.2 章中也讨论了这种方法。 -
@ichistmeinname 我对
open_rec_lc_core的证明很感兴趣,你是怎么证明的?