[英]Coq: Rewriting with 'forall' in hypothesis or goal
我已經證明了Coq中多態列表的反函數的“正確性”。 以下證明工作正常,但我有一些關於重寫策略如何工作的問題。
這是代碼:
Require Export Coq.Lists.List.
Import ListNotations.
Fixpoint rev {T:Type} (l:list T) : list T :=
match l with
| nil => nil
| h :: t => rev t ++ [h]
end.
(* Prove rev_acc equal to above naive implementation. *)
Fixpoint rev_acc {T:Type} (l acc:list T) : list T :=
match l with
| nil => acc
| h :: t => rev_acc t (h::acc)
end.
Theorem app_assoc : forall (T:Type) (l1 l2 l3 : list T),
(l1 ++ l2) ++ l3 = l1 ++ (l2 ++ l3).
Proof.
Admitted.
Theorem rev_acc_correct : forall (T:Type) (l k :list T),
rev l ++ k = rev_acc l k.
Proof.
intros T l.
induction l as [ | h l' IHl' ].
- reflexivity.
- simpl.
intro k.
(* Why is "intro k" required for "rewrite -> app_assoc" *)
(* But "rewrite -> IHl'" works regardless of "intro k". *)
(* generalize (rev l'), [h], k. *)
rewrite -> app_assoc.
simpl.
rewrite -> IHl'.
reflexivity.
Qed.
在rev_acc_correct的證明的歸納步驟中,如果我跳過介紹k ,那么用app_assoc重寫會抱怨它無法找到匹配的子項。
Found no subterm matching "(?M1058 ++ ?M1059) ++ ?M1060" in the current goal.
在這里,我認為是? 在占位符名稱之前表示術語是約束的,在這種情況下,對於某些類型T ,它是類型為List T的類型; 並且由於目標中的rev l'和[h]是List T的實例,因此可以預期目標中的匹配。
另一方面,使用歸納假設( 重寫 - > IHl' )而不是app_assoc進行重寫 ,而不需要前面的介紹k 。
我發現這種重寫行為有點令人困惑,Coq手冊沒有提供任何細節。 我不想閱讀實現,但我需要對重寫策略的作用有一個良好的操作理解,特別是關於術語匹配如何工作。 任何在這個方向的答案/參考都非常感謝。
這種重寫的復雜性在於有一個綁定器 ( forall k
),它可以使事情變得復雜。 如果你只是想要工作,使用setoid_rewrite
而不是rewrite
,它將在綁定器下重寫。
rewrite IHl'
看起來像是在綁定器下發生,但rewrite IHl'
的模式實際上並不涉及綁定變量,因此綁定器實際上並不重要。 這就是我的意思:目標是
forall k : list T, (rev l' ++ [h]) ++ k = rev_acc l' (h :: k)
這與(即等於)相同:
(fun l : list T => forall k : list T, l ++ k = rev_acc l' (h :: k)) (rev l' ++ [h])
我在Ltac中使用了pattern (rev l' ++ [h])
。 現在很明顯,您可以只重寫正在應用的部分並忽略活頁夾。 當你rewrite IHl'
時,很容易發現IHl
應該專門用於[h]
並且重寫繼續進行。
rewrite app_assoc
需要專門針對三個列表,特別是rev l'
, [h]
和k
。 它不能專門用於當前上下文,因為變量k
僅綁定在forall
下面。 這就是為什么模式(?x ++ ?y) ++ ?z
沒有出現在目標中。 那你究竟做了什么? 你當然可以介紹k
所以沒有綁定器,但有一種更簡單,更通用的技術:Coq具有可以在綁定器下重寫的通用重寫,你可以使用它來代替調用setoid_rewrite
(參見Coq參考手冊中的綁定下重寫 ) 。 手冊告訴你需要聲明態射,但是在這種情況下相關的已經為你實現了forall
,所以setoid_rewrite app_assoc
將正常工作。
請注意,雖然你總是可以引入一個forall
來擺脫綁定, setoid_rewrite
當你的目標exists
時, setoid_rewrite
可以非常方便。 您可以在綁定器下重寫,而不是使用eexists
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.