[英]How to solve goals with invalid type equalities in Coq?
我的證明腳本給了我愚蠢的類型,如nat = bool
或nat = list unit
,我需要用它來解決相互矛盾的目標。
在正常的數學中,這將是微不足道的。 給定bool := { true, false }
和nat := { 0, 1, 2, ... }
我知道true ∈ bool
,但是true ∉ nat
,因此bool ≠ nat
。 在Coq,我甚至不知道如何說明這一點true :̸ nat
。
有沒有辦法證明這些平等是錯誤的? 或許,這不可能嗎?
(編輯:刪除了一長串失敗的attemts,仍然可以在歷史上看到。)
tl; dr基數參數是顯示不等等類型的唯一方法。 你可以通過一些反思更有效地自動化基數論證。 如果你想更進一步,通過構建一個宇宙給你的類型一個句法表示,確保你的證明義務被表述為表示的句法不等式而不是類型的語義不等式。
人們普遍認為(並且甚至可能存在某種證據),Coq的邏輯與同構集在命題上相等的公理是一致的。 事實上,這是弗拉基米爾·沃沃茨基(Vladimir Voevodsky)的“單一公理”(Univalence Axiom)的結果,人們現在正享受着如此多的樂趣。 我必須說,似乎非常合理的是它是一致的(在沒有typecase的情況下),並且可以構造計算解釋,它通過插入在任何給定時刻需要同構的任何組件以某種方式在相等類型之間傳輸值。
如果我們假設這樣的公理是一致的,我們發現邏輯中的類型不等式只能通過反駁類型同構的存在來保持。 因此,至少在原則上,您的部分解決方案是在哪里。 可枚舉性是顯示非同構性的關鍵。 我不確定nat = (nat -> nat)
的狀態是什么,但是從系統外部可以清楚地知道nat -> nat
每個居民都有一個正常的形式,並且有很多正常的形式:至少有道理,有一致的公理或反思原則使邏輯更具有內涵 ,並證實了這一假設。
我可以看到你可能采取的兩個步驟來改善現狀。 較不激進的步驟是通過更好地利用反射來改進您的通用技術,以便制作這些基數論證。 理想情況下,您可以這樣做,因為一般來說,您希望證明有限集與某些較大集不同。 假設我們有一些DList A
概念,這是A
的不同元素的列表。 如果你可以構造一個詳盡的 DList A
和一個更長的 DList B
,那么你可以反駁A = B
通過歸納遞歸有一個可愛的DList定義,但Coq沒有歸納遞歸。 幸運的是,這是我們可以通過仔細使用索引來模擬的定義之一。 請原諒我的非正式語法,但我們有
Parameters
A : Set
d : A -> A -> bool
dok : forall x y, d x y = true -> x = y -> False
這就是d
為“不同”。 如果一組已擁有可判定的平等,你可以用它裝備d
變得非常容易。 一套大型設備可以配備足夠的d
用於我們的目的而沒有太多的工作。 實際上,這是至關重要的一步:遵循SSReflect團隊的智慧,我們通過使用bool
而不是Prop
來利用我們領域的小巧,並使計算機完成繁重的任務。
現在,讓我們來
DListBody : (A -> bool) -> Set
其中索引是列表的新鮮度測試
dnil : DListBody (const true) (* any element is fresh for the empty list *)
dsnoc : forall f, (xs : DListBody f) -> (x : A) -> is_true (f x) ->
DListBody (fun y => f y /\ d x y)
如果你喜歡,你可以定義DList
包裝DListBody
存在性。 也許這實際上隱藏了我們想要的信息,因為要顯示這樣一個詳盡無遺的信息是這樣的:
Exhaustive (f : A -> bool)(mylist : DListBody f) = forall x : A, is_false (f x)
因此,如果您可以為有限枚舉寫下DListBody,您可以通過簡單的子目標進行案例分析來證明它是詳盡無遺的。
然后你只需要做一次鴿子爭論。 如果你想反駁類型之間的相等(假設你已經有合適的d
候選者),你可以詳盡地枚舉較小的並且從較大的列表中展示一個較長的列表,就是這樣。
更激進的選擇是質疑為什么你首先要實現這些目標,以及它們是否真正意味着你想要它們。 應該是什么類型,真的嗎? 這個問題有多種可能的答案,但它至少是開放的,它們在某種意義上是“基數”。 如果你想將類型視為更具體和語法,如果它們是由不同的結構構建的,那么你可能需要通過在Universe中工作來為類型配備更具體的表示。 您可以為類型定義“名稱”的歸納數據類型,以及將名稱解碼為類型的方法,然后根據名稱重新構建開發。 您應該發現名稱的不等式遵循普通的構造函數歧視。
問題在於Coq中的宇宙構造可能有點棘手,因為不支持感應遞歸。 這在很大程度上取決於您需要考慮的類型。 也許你可以歸納地定義一些U : Set
然后實現一個遞歸解碼器T : U -> Set
。 對於簡單類型的宇宙來說,這當然是合理的。 如果你想要一個依賴類型的世界,事情會變得有點汗流。背。 你至少可以這么做
U : Type (* note that we've gone up a size *)
NAT : U
PI : forall (A : Set), (A -> U) -> U
T : U -> Set
T NAT = nat
T (PI A B) = forall (a : A), T (B a)
但請注意, PI
的域在Set
未編碼,而不是在U
。 歸納遞歸的Agdans可以克服這個問題,同時定義U
和T
U : Set (* nice and small *)
NAT : U
PI : forall (A : U), (T A -> U) -> U (* note the use of T *)
T : U -> Set
T NAT = nat
T (PI A B) = forall (a : T A), T (B a)
但是Coq不會那樣。 同樣,解決方法是使用索引。 這里的成本是U
不可避免地很大。
U : Set -> Type
NAT : U nat
PI : forall (A : Set)(B : A -> Set),
U A -> (forall a, U (B a)) -> U (forall a, B a)
但是你仍然可以通過這種方式構建宇宙來完成很多工作。 例如,人們可以為這樣的宇宙配備計算有效的拉伸等式 。
作為參考,這是我對nat = bool -> False
證明。 (這很長,但我希望很容易看出這個證明的一般結構。)
Goal nat = bool -> False.
(* For any two types, if they are actually identical, the identity is an
isomorphism. *)
assert (forall (T U : Set), T = U ->
exists (f : T -> U) (g : U -> T),
(forall t, (g (f t)) = t) /\ (forall u, (f (g u)) = u))
as Hiso
by (intros T U H; rewrite H; exists (@id U); exists (@id U);
split; intro; reflexivity).
(* our nat = bool *)
intro HC.
(* combining the facts gives an iso between nat and bool *)
pose proof (Hiso nat bool HC); clear HC Hiso.
inversion H as [phi [phi_inv [Hl Hr]]]; clear H Hr.
(* this breaks because ||bool|| = 2 while ||nat|| > 2 -- we get collisions *)
assert (forall m n o,
phi m = phi n \/ phi n = phi o \/ phi m = phi o)
by (intros m n o;
case (phi m); case (phi n); case (phi o); clear; tauto).
(* building the collision for 0, 1 and 2 *)
pose proof (H 0 1 2) as HC; clear H.
(* (false) identity preservation for 0, 1, 2 *)
pose proof (Hl 0) as H0; pose proof (Hl 1) as H1;
pose proof (Hl 2) as H2; clear Hl.
(* case analysis on phi calls yields equalities on non-equal numbers... *)
destruct (phi 0); destruct (phi 1); destruct (phi 2);
(* ...rewriting leads to an equality '0 = 2' or '0 = 1' or '1 = 2'... *)
try (rewrite H2 in H0); try (rewrite H1 in H0); try (rewrite H2 in H1);
(* ...which can be used to solve by constructor inequality *)
try inversion H0; inversion H1.
Qed.
正如您所看到的,這對於大型有限類型(即使是自動化的)也不是真的可用 - 這些術語太大了。 對此的任何改進都會很棒。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.