簡體   English   中英

歧視策略如何運作?

[英]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等於xP 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的前兩個參數,我們還需要三個:分支的證明,其中xA ,這是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的定義
  • 完整的模式匹配語法,包含asinreturn術語

首先,我們可以看一下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 = yx是參數,而y是索引。 也就是說, x在所有構造x是恆定的,而y在每個構造函數中可以是不同的。 您與Vector.t類型有相同的區別。 如果添加元素,向量元素的類型將不會更改,這就是它作為參數實現的原因。 然而,它的大小可以改變,這就是它作為索引實現的原因。

現在,讓我們看一下擴展模式匹配語法。 我在這里簡單解釋一下我所理解的內容。 請不要猶豫,查看參考手冊以獲取更安全的信息。 return子句可以幫助指定每個分支的返回類型。 該子句可以使用模式匹配的asin子句中定義的變量,它們分別綁定匹配的術語和類型索引。 return子句將在每個分支的上下文中解釋,用asin的變量替換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_reflc等於A (因為eq_refl的定義實例化了與參數具有相同值的索引),因此我們聲稱我們返回了一些True類型的值,這里是I 但是從外部角度來看, c等於B (因為eA=B的類型),這次return子句聲稱match返回一些False類型的值。 我們在這里使用Coq的功能來簡化我們在test2看到的類型中的模式匹配。 請注意,我們在除B之外的其他情況下使用True ,但我們並不特別需要True 我們只需要一些有人居住的類型,這樣我們就可以在eq_refl分支中返回一些eq_refl

回到Coq產生的奇怪術語,Coq使用的方法做了類似的事情,但在這個例子中,肯定更復雜。 特別是,勒柯克經常使用類型IDProp聚居idProp時,它需要無用的類型和條款。 它們對應於TrueI在上面使用過。

最后,我給出了關於coq-club的討論鏈接 ,這真正幫助我理解了如何在Coq中輸入擴展模式匹配。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM