在简单类型的lambda演算中输入推导是唯一的证据在纸面上是微不足道的。我熟悉的证据是通过对输入派生的完全归纳来进行的。但是,我无法证明键入派生,表示通过类型的输入派生,是唯一的。如果变量dec Γ x τ
在环境x
中的类型为τ
,则谓词Γ
为true。打字谓词J
是通常定义的,只需读取简单类型的lambda演算的输入规则:
Inductive J (Γ : env) : term → type → Set :=
| tvar : ∀ x τ, dec Γ x τ → J γ (var x) τ
| tabs : ∀ τ₁ τ₂ e, J (τ₁ :: γ) e τ₂ → J γ (abs τ₁ e) (arr τ₁ τ₂)
| tapp : ∀ τ₁ τ₂ e₁ e₂, J γ e₁ (arr τ₁ τ₂) → J γ e₂ τ₁ → J γ (app e₁ e₂) τ₂.
在证明输入派生是唯一的时,我无法公开类型J
的结构。例如,我可以在以下引理中引入d1
或d2
,但不能在d1
上导入,然后在相反的情况下破坏d2
。 Coq给出的错误消息(抽象术语导致一个类型错误的术语)有点模糊,而Coq wiki没有提供任何帮助。作为参考,这是我试图证明的引理:
Lemma unique_derivation : ∀ Γ e τ (d₁ d₂ : J Γ e τ), d₁ = d₂.
在引入条款时我没有问题,例如,在证明类型是唯一的时候。
编辑:我添加了说明我遇到问题的结果所需的最少数量的定义。为了回应huitseeker的评论,选择了J
,因为我想推断将派生类型作为结构化对象来进行,以便执行提取等操作并证明结果如唯一性,这在我之前没有在Coq中完成。
在回复评论的第一部分时,我可以induction
或d1
执行d2
,但执行induction
后我无法在剩余的期限内使用destruct
,case
或induction
。这意味着我无法公开d1
和d2
的结构以推理两个证明树。我在尝试这样做时收到的错误表示,对剩余的术语进行抽象会导致一个类型错误的术语。
Require Import Unicode.Utf8.
Require Import Utf8_core.
Require Import List.
Inductive type : Set :=
| tau : type
| arr : type → type → type.
Inductive term : Set :=
| var : nat → term
| abs : type → term → term
| app : term → term → term.
Definition dec (Γ : list type) x τ : Prop :=
nth_error γ x = Some τ.
Inductive J (Γ : list type) : term → type → Set :=
| tvar : ∀ x τ, dec Γ x τ → J Γ (var x) τ
| tabs : ∀ τ₁ τ₂ e, J (τ₁ :: Γ) e τ₂ → J Γ (abs τ₁ e) (arr τ₁ τ₂)
| tapp : ∀ τ₁ τ₂ e₁ e₂, J Γ e₁ (arr τ₁ τ₂) → J Γ e₂ τ₁ → J Γ (app e₁ e₂) τ₂.
Lemma derivations_unique : ∀ Γ e τ (d1 d2 : J Γ e τ), d1 = d2.
Proof. admit. Qed.
我尝试过使用dependent induction
和Coq.Logic
库中的一些结果,但没有成功。这些推导是独一无二的,似乎应该是一个容易证明的命题。
答案 0 :(得分:1)
你有三个问题。
一个是使感应工作的纯粹技术问题。您可以使用dependent destruction
策略解决主要难题(由Matthieu Sozeau on the Coq-Club mailing list提供)。这是一种反转策略。我不会假装了解它是如何工作的。
第二个困难是在一个基本案例中,对于环境。您需要证明list nat
中的等式证明是唯一的;这适用于所有可判定的域,其工具位于Eqdep_dec模块中。
第三个困难是与问题有关。推导的唯一性并不依赖于对术语或派生结构的直接归纳,因为您的术语没有足够的类型信息来重构派生。在应用程序app e1 e2
中,没有直接的方法来了解参数的类型。在简单类型的lambda演算中,类型重建确实成立,并且很容易证明;在较大的计算(具有多态或子类型)中,它可能不成立(例如,使用ML样式的多态,有一个唯一的主类型方案和相关的派生,但有很多使用基类型的派生)
这是你的引理的快速证明。我省略了环境查找的单一性证明。你可以引入术语结构或派生结构 - 这个简单的证明是有效的,因为它们是相同的。
Require Import Unicode.Utf8.
Require Import Utf8_core.
Require Import List.
Require Import Program.Equality.
Inductive type : Set :=
| tau : type
| arr : type → type → type.
Inductive term : Set :=
| var : nat → term
| abs : type → term → term
| app : term → term → term.
Definition dec (Γ : list type) x τ : Prop :=
nth_error Γ x = Some τ.
Inductive J (Γ : list type) : term → type → Set :=
| tvar : ∀ x τ, dec Γ x τ → J Γ (var x) τ
| tabs : ∀ τ₁ τ₂ e, J (τ₁ :: Γ) e τ₂ → J Γ (abs τ₁ e) (arr τ₁ τ₂)
| tapp : ∀ τ₁ τ₂ e₁ e₂, J Γ e₁ (arr τ₁ τ₂) → J Γ e₂ τ₁ → J Γ (app e₁ e₂) τ₂.
Lemma unique_variable_type :
forall G x t1 t2, dec G x t1 -> dec G x t2 -> t1 = t2.
Proof.
unfold dec; intros.
assert (value t1 = value t2). congruence.
inversion H1. reflexivity.
Qed.
Axiom unique_variable_type_derivation :
forall G x t (d1 d2 : dec G x t), d1 = d2.
Lemma unique_type : forall G e t1 t2 (d1 : J G e t1) (d2 : J G e t2), t1 = t2.
Proof.
intros G e; generalize dependent G.
induction e; intros.
dependent destruction d1. dependent destruction d2.
apply (unique_variable_type G n); assumption.
dependent destruction d1. dependent destruction d2.
firstorder congruence.
dependent destruction d1. dependent destruction d2.
assert (arr τ₁ τ₂ = arr τ₁0 τ₂0).
firstorder congruence.
congruence.
Qed.
Lemma unique_derivation : forall G e t (d1 d2 : J G e t), d1 = d2.
Proof.
intros G e; generalize dependent G.
induction e; intros.
dependent destruction d1. dependent destruction d2.
f_equal. solve [apply (unique_variable_type_derivation G n)].
dependent destruction d1. dependent destruction d2.
f_equal. solve [apply IHe].
dependent destruction d1. dependent destruction d2.
assert (τ₁ = τ₁0). 2: subst τ₁.
solve [eapply unique_type; eauto].
f_equal; solve [firstorder].
Qed.