[英]How does the discriminate tactic work?
我很好奇這種discriminate
策略是如何在幕后工作的。 因此我做了一些實驗。
首先是一個簡單的歸納定義:
Inductive AB:=A|B.
然后是一個簡單的引理,可以通過discriminate
策略證明:
Lemma l1: A=B -> False.
intro.
discriminate.
Defined.
讓我們看看證明的樣子:
Print l1.
l1 =
fun H : A = B =>
(fun H0 : False => False_ind False H0)
(eq_ind A
(fun e : AB => match e with
| A => True
| B => False
end) I B H)
: A = B -> False
這看起來相當復雜,我不明白這里發生了什么。 因此,我試圖更明確地證明相同的引理:
Lemma l2: A=B -> False.
apply (fun e:(A=B) => match e with end).
Defined.
讓我們再看看Coq用這個做了什么:
Print l2.
l2 =
fun e : A = B =>
match
e as e0 in (_ = a)
return
(match a as x return (A = x -> Type) with
| A => fun _ : A = A => IDProp
| B => fun _ : A = B => False
end e0)
with
| eq_refl => idProp
end
: A = B -> False
現在我完全糊塗了。 這還是比較復雜的。 誰能解釋一下這里發生了什么?
讓我們l1
這個l1
術語並描述它的每個部分。
l1 : A = B -> False
l1
是一個含義,因此通過Curry-Howard對應它是一個抽象(函數):
fun H : A = B =>
現在我們需要構造抽象體,它必須具有False
類型。 discriminate
策略選擇將主體實現為應用程序fx
,其中f = fun H0 : False => False_ind False H0
並且它只是False
的歸納原理的包裝,它說如果你有一個False
的證明,你可以得到你想要的任何命題的證明( False_ind : forall P : Prop, False -> P
):
(fun H0 : False => False_ind False H0)
(eq_ind A
(fun e : AB => match e with
| A => True
| B => False
end) I B H)
如果我們執行beta減少的一個步驟,我們將簡化以上內容
False_ind False
(eq_ind A
(fun e : AB => match e with
| A => True
| B => False
end) I B H)
False_ind
的第一個參數是我們正在構建的術語的類型。 如果你要證明A = B -> True
,它將是False_ind True (eq_ind A ...)
。
順便說一句,很容易看出我們可以進一步簡化我們的身體 - 為了讓False_ind
工作,它需要提供一個False
的證明,但這正是我們在這里想要構建的! 因此,我們可以完全擺脫False_ind
,得到以下內容:
eq_ind A
(fun e : AB => match e with
| A => True
| B => False
end) I B H
eq_ind
是平等的歸納原則,說等於可以代替等於:
eq_ind : forall (A : Type) (x : A) (P : A -> Prop),
P x -> forall y : A, x = y -> P y
換句話說,如果一個人有P x
的證明,那么對於所有y
等於x
, P y
成立。
現在,讓我們使用eq_ind
逐步創建一個False
證明(最后我們應該獲得eq_ind A (fun e : AB ...)
術語)。
當然,我們從eq_ind
,然后我們將它應用於某些x
- 讓我們使用A
來達到這個目的。 接下來,我們需要謂詞P
寫下P
時要記住的一件重要事情是我們必須能夠證明P x
。 這個目標很容易實現 - 我們將使用True
命題,它有一個微不足道的證明。 要記住的另一件事是我們試圖證明的命題( False
) - 如果輸入參數不是A
我們應該返回它。 有了以上所有,謂詞幾乎寫出了自己:
fun x : AB => match x with
| A => True
| B => False
end
我們有eq_ind
的前兩個參數,我們還需要三個:分支的證明,其中x
是A
,這是True
的證明,即I
一些y
,它將引導我們得到我們想要證明的命題,即B
,以及A = B
的證明,在這個答案的最開始時稱為H
把它們堆疊在一起我們得到了
eq_ind A
(fun x : AB => match x with
| A => True
| B => False
end)
I
B
H
這正是discriminate
給我們的東西(模數包裝)。
另一個答案集中在歧視部分,我將重點關注手動證明。 你試過:
Lemma l2: A=B -> False.
apply (fun e:(A=B) => match e with end).
Defined.
應該注意並使我經常使用Coq感到不舒服的是,Coq接受了錯誤定義的定義,它在內部重寫為良好類型的術語。 這樣可以減少冗長,因為Coq自己添加了一些部分。 但另一方面,Coq操縱的術語與我們輸入的術語不同。
您的證明就是這種情況。 當然, e
上的模式匹配應該包含構造函數eq_refl
,它是eq
類型的單個構造函數。 在這里,Coq檢測到相等性沒有居住,因此了解如何修改代碼,但是您輸入的內容不是正確的模式匹配。
兩種成分可以幫助理解這里發生的事情:
eq
的定義 as
, in
和return
術語 首先,我們可以看一下eq
的定義。
Inductive eq {A : Type} (x : A) : A -> Prop := eq_refl : x = x.
請注意,此定義與看起來更自然(在任何情況下,更對稱)的定義不同。
Inductive eq {A : Type} : A -> A -> Prop := eq_refl : forall (x:A), x = x.
使用第一個定義而不是第二個定義來定義eq
非常重要。 特別是,對於我們的問題,重要的是,在x = y
, x
是參數,而y
是索引。 也就是說, x
在所有構造x
是恆定的,而y
在每個構造函數中可以是不同的。 您與Vector.t
類型有相同的區別。 如果添加元素,向量元素的類型將不會更改,這就是它作為參數實現的原因。 然而,它的大小可以改變,這就是它作為索引實現的原因。
現在,讓我們看一下擴展模式匹配語法。 我在這里簡單解釋一下我所理解的內容。 請不要猶豫,查看參考手冊以獲取更安全的信息。 return
子句可以幫助指定每個分支的返回類型。 該子句可以使用模式匹配的as
和in
子句中定義的變量,它們分別綁定匹配的術語和類型索引。 return
子句將在每個分支的上下文中解釋,用as
和in
的變量替換in
使用此上下文逐個類型檢查分支,並用於從外部角度鍵入match
。
這是一個帶有as
子句的人為例子:
Definition test n :=
match n as n0 return (match n0 with | 0 => nat | S _ => bool end) with
| 0 => 17
| _ => true
end.
根據n
的值,我們不會返回相同的類型。 test
的類型是forall n : nat, match n with | 0 => nat | S _ => bool end
forall n : nat, match n with | 0 => nat | S _ => bool end
forall n : nat, match n with | 0 => nat | S _ => bool end
。 但是當Coq可以決定我們匹配的情況時,它可以簡化類型。 例如:
Definition test2 n : bool := test (S n).
在這里,Coq知道,無論n
是什么,給予test
S n
都會產生類型為bool
東西。
為了平等,我們可以做類似的事情,這次使用in
子句。
Definition test3 (e:A=B) : False :=
match e in (_ = c) return (match c with | B => False | _ => True end) with
| eq_refl => I
end.
這里發生了什么 ? 從本質上講,Coq類型分別檢查match
的分支和match
本身。 在唯一的分支eq_refl
, c
等於A
(因為eq_refl
的定義實例化了與參數具有相同值的索引),因此我們聲稱我們返回了一些True
類型的值,這里是I
但是從外部角度來看, c
等於B
(因為e
是A=B
的類型),這次return
子句聲稱match
返回一些False
類型的值。 我們在這里使用Coq的功能來簡化我們在test2
看到的類型中的模式匹配。 請注意,我們在除B
之外的其他情況下使用True
,但我們並不特別需要True
。 我們只需要一些有人居住的類型,這樣我們就可以在eq_refl
分支中返回一些eq_refl
。
回到Coq產生的奇怪術語,Coq使用的方法做了類似的事情,但在這個例子中,肯定更復雜。 特別是,勒柯克經常使用類型IDProp
聚居idProp
時,它需要無用的類型和條款。 它們對應於True
, I
在上面使用過。
最后,我給出了關於coq-club的討論鏈接 ,這真正幫助我理解了如何在Coq中輸入擴展模式匹配。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.