簡體   English   中英

Coq - 返回類型的值,它等於函數返回類型

[英]Coq - return value of type which is equal to function return type

根據某些定理,我們知道類型A等於類型B 在類型檢查期間如何告訴Coq編譯器?

我想實現一個非空樹,以便每個節點都知道它的大小:

Inductive Struct: positive -> Type :=
| Leaf : Struct 1%positive
| Inner: forall {n m}, Struct n -> Struct m -> Struct (n + m).

我想創建一個函數,生成給定大小的對數深度的樹。 例如

7 -> 6 + 1 -> (3 + 3) + 1 -> ((2 + 1) + (2 + 1)) + 1 -> (((1 + 1) + 1) + ((1 + 1) + 1)) + 1

Fixpoint nat2struct n : (Struct n) :=
  match n with
  | xH => Leaf
  | xO n => Inner (nat2struct n) (nat2struct n) 
  | xI n => Inner Leaf (Inner (nat2struct n) (nat2struct n))
  end.

但是,我收到錯誤:

術語“內葉(內部(nat2struct n0)(nat2struct n0))”具有類型“Struct(1 +(n0 + n0))”,而期望具有類型“Struct n0~1”。

我怎樣才能解決這個問題? 我們知道(1 + n + n) = xI n ,但Coq沒有。 如果我之前說過這個定理,它不會改變任何東西:

Theorem nBy2p1: forall n, Pos.add 1%positive (n + n) = xI n. Proof. Admitted.
Hint Resolve nBy2p1.

是否有一些提示讓Coq知道這個定理?

PS1:這個定理已經在標准庫中證明了嗎? 我找不到一個。

PS2:我實際上想要更自然地分裂: 7 -> 4 + 3 -> (2 + 2) + (2 + 1) -> ((1 + 1) + (1 + 1)) + ((1 + 1) + 1) 可能嗎? 我不知道如何編寫它以便Coq理解函數收斂。

在類型檢查時,Coq使用較弱的相等形式(有時稱為定義,判斷或計算相等)。 與命題相等(默認情況下“=”綁定)不同,定義相等是可判定的。 Coq可以采取任何兩個術語,並決定一個是否可以轉換為另一個。 如果在類型檢查中允許使用命題相等,則類型檢查將不再是可判定的1

要解決您的問題(這是一個非常大的問題),您有幾個選擇。

使Struct成為記錄

我將使用列表演示原理。 首先,我們有未列出的列表的概念。

Inductive UnsizedList (A: Type) :=
| unil
| ucons (a: A) (u: UnsizedList A).

Arguments unil [A], A.
Arguments ucons [A] a u, A a u.

Fixpoint length {A: Type} (u: UnsizedList A) :=
match u with
| unil => 0
| ucons _ u' => S (length u')
end.

我們還可以定義一個大小的列表,其中SizedList A n每個元素的長度為n

Inductive SizedList (A: Type): nat -> Type :=
| snil: SizedList A 0
| scons {n: nat} (a: A) (u: SizedList A n): SizedList A (S n).

此定義與您的問題完全相同。 例如,如果要顯示串聯是關聯的,則不能簡單地證明concat (concat uv) w = concat u (concat vw) ,因為等式的兩邊有不同的類型( (i + j) + k vs i + (j + k) )。 如果我們可以簡單地告訴Coq我們期望列表的大小,那么稍后證明,我們可以解決這個問題。 這就是這個定義的作用,它將UnsizedList打包在一起,證明該列表具有所需的長度。

Record SizedListPr (A: Type) (n: nat): Type := {
  list: UnsizedList A;
  list_len_eq: length list = n;
}.

現在我們可以有concat (concat uv) w = concat u (concat vw) ; 我們只需要證明雙方都有長度(i + j) + k

使用強制

如果你不小心這種方法會變得非常混亂,所以它通常不是首選的方法。

讓我定義一種強制,如果x = y則將P x類型的元素映射到P y類型的元素。 2

Definition coercion {A: Type} (P: A -> Type) {x y: A} (p: x = y): P x -> P y :=
match p with
| eq_refl => fun t => t
end.

這里我們在術語p: x = y上使用歸納法。 歸納原則基本上說,如果我們能夠在xy在定義上相等時證明某些東西,那么我們可以在它們的命題相等時證明它。 3P xP y相同時,我們可以使用身份函數。

現在,例如,大小列表的連接的關聯性聲明是concat (concat uv) w = coercion (SizedList A) (add_assoc) (concat u (concat vw)) 所以我們使用SizedList A (i + (j + k))類型為SizedList A (i + (j + k))的類型SizedList A ((i + j) + k)為類型為SizedList A ((i + j) + k)add_assoc: i + (j + k) = (i + j) + k (為了便於閱讀,我省略了一些參數)。


你做出的選擇取決於你。 有關此問題及相關問題的討論以及一些其他解決方案可在“ 依賴類型認證編程”頁面“ 平等”中找到


1對於一類通常會發生這種理論的理論,請參見拉伸型理論 馬丁霍夫曼的論文概述了內涵和外延理論之間的區別。

2如果您熟悉同倫類型理論,那就是transport

3在這一陳述中有足夠的警告說,命題和定義平等之間的差異仍然存在。

根據用戶的回答,這是我最終得到的解決方案:

Inductive Struct: positive -> Type :=
| Leaf : Struct 1
| Inner : forall {lsize rsize size}
    (proof: Pos.add lsize rsize = size),
    (Struct lsize) -> (Struct rsize) -> Struct size.

Local Lemma nBy2: forall {n}, Pos.add n n = xO n.
Proof.
intros.
assert (Zpos (n + n) = Zpos (n~0)). { rewrite Pos2Z.inj_add. rewrite Z.add_diag. symmetry. apply Pos2Z.inj_xO. }
inversion H. auto.
Qed.

Local Lemma nBy2p1: forall {n}, Pos.add 1 (xO n) = xI n.
Proof.
intros. simpl.
assert (Zpos (1 + n~0) = Zpos (n~1)). { rewrite Pos2Z.inj_add. reflexivity. }
inversion H. auto.
Qed.

Fixpoint structCreate (size : positive) : (Struct size) :=
  match size with
  | xH => Leaf
  | xO n =>
    let child := structCreate n in
    Inner nBy2 child child
  | xI n => 
    let child := structCreate n in
    Inner nBy2p1 Leaf (Inner nBy2 child child)
  end.

暫無
暫無

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

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