<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Software Foundations Vol.I : 使用結構化的數據(Lists)

      Software Foundations Vol.I : 使用結構化的數據(Lists)


      數值序對

      在 Inductive 類型定義中,每個構造子(Constructor)可以有任意多個參數 —— 可以沒有(如 true 和 O),可以只有一個(如 S),也可以更多 (如 nybble,以及下文所示):

      Inductive natprod : Type :=
      | pair (n1 n2 : nat).
      
      Check (pair 3 5) : natprod.
      
      Definition fst (p : natprod) : nat :=
        match p with
        | pair x y ? x
        end.
      Definition snd (p : natprod) : nat :=
        match p with
        | pair x y ? y
        end.
      Compute (fst (pair 3 5)).
      (* ===> 3 *)
      

      由于二元組十分常用,不妨以標準的數學記法 (x,y) 取代 pair x y。 通過 Notation 向 Coq 聲明該記法:

      Notation "( x , y )" := (pair x y).
      

      這種新的表示法既可以在表達式中使用,也可以在模式匹配中使用.

      Compute (fst (3,5)).
      Definition fst' (p : natprod) : nat :=
        match p with
        | (x,y) ? x
        end.
      Definition snd' (p : natprod) : nat :=
        match p with
        | (x,y) ? y
        end.
      Definition swap_pair (p : natprod) : natprod :=
        match p with
        | (x,y) ? (y,x)
        end.
      

      對一個括號內的元組(如:(x,y)),并非與先前所見的多重匹配語法(如 x,y)混淆.

      這種差異雖然不大,但是了解到這一點還是非常必要的.例如,下面的定義就是不正確的:

      (* Can't match on a pair with multiple patterns: *)
      Definition bad_fst (p : natprod) : nat :=
        match p with
        | x, y ? x
        end.
      
      (* Can't match on multiple values with pair patterns: *)
      Definition bad_minus (n m : nat) : nat :=
        match n, m with
        | (O , _ ) ? O
        | (S _ , O ) ? n
        | (S n', S m') ? bad_minus n' m'
        end.
      

      如果我們以稍顯古怪的方式陳述序對的性質,那么有時只需 reflexivity(及其內建的簡化)即可完成證明。

      Theorem surjective_pairing' : ? (n m : nat),
        (n,m) = (fst (n,m), snd (n,m)).
      Proof.
        reflexivity. Qed.
      

      但是,如果我們用一種更為自然的方式來陳述此引理的話,只用 reflexivity 還不夠。

      Theorem surjective_pairing_stuck : ? (p : natprod),
        p = (fst p, snd p).
      Proof.
        simpl. (* 啥也沒有歸約! *)
      Abort.
      

      我們還需要向 Coq 展示 p 的具體結構,這樣 simpl 才能對 fst 和 snd 做模式匹配。通過 destruct 可以達到這個目的

      Theorem surjective_pairing : forall (p : natprod),
        p = (fst p, snd p).
      Proof.
        intros p. 
        destruct p as [n m]. 
        - simpl. 
          reflexivity. 
      Qed.
      

      數值列表

      通過推廣序對的定義,數值'列表'類型可以這樣描述: “一個列表要么是空的,要么就是由一個數和另一個列表組成的序對。”

      Inductive natlist : Type :=
        | nil
        | cons (n : nat) (l : natlist).
      

      例如,這是一個三元素列表:

      Definition mylist := cons 1 (cons 2 (cons 3 nil)).
      

      和序對一樣,使用熟悉的編程記法來表示列表會更方便些。 以下兩個聲明能讓我們用 :: 作為中綴的 cons 操作符, 用方括號作為構造列表的“外圍(outfix)”記法。

      Notation "x :: l" := (cons x l)
        (at level 60, right associativity).
      Notation "[ ]" := nil.
      Notation "[ x ; .. ; y ]" := 
        (cons x .. (cons y nil) ..).
      

      注解 "right associativity" 告訴 Coq 當遇到多個 :: 時如何給表達式加括號,如此一來下面三個聲明做的就是同一件事:

      Definition mylist1 := 1 :: (2 :: (3 :: nil)).
      Definition mylist2 := 1 :: 2 :: 3 :: nil.
      Definition mylist3 := [1;2;3].
      

      "at level 60" 告訴 Coq 當遇到表達式和其它中綴運算符時應該如何加括號。 例如,plus 函數定義了 + 中綴符號,它的優先級是 50:

      Notation "x + y" := (plus x y)
        (at level 50, left associativity).
      

      +會比 :: 結合的更緊密,所以 1 + 2 :: [3] 會被解析成 (1 + 2) :: [3] 而非 1 + (2 :: [3])。

      Repeat

      接下來看幾個用來構造和操作列表的函數。第一個是 repeat 函數,它接受一個數字 n 和一個 count,返回一個長度為 count,每個元素都是 n 的列表。

      Fixpoint repeat (n count : nat) : natlist :=
        match count with
        | O ? nil
        | S count' ? n :: (repeat n count')
        end.
      

      Length

      length 函數用來計算列表的長度。

      Fixpoint length (l:natlist) : nat :=
        match l with
        | nil ? O
        | h :: t ? S (length t)
        end.
      

      Append

      app 函數用來把兩個列表聯接起來。

      Fixpoint app (l1 l2 : natlist) : natlist :=
        match l1 with
        | nil ? l2
        | h :: t ? h :: (app t l2)
        end.
      

      由于下文中 app 隨處可見,不妨將其定義為中綴運算符。

      Notation "x ++ y" := (app x y)
                           (right associativity, at level 60).
      Example test_app1: [1;2;3] ++ [4;5] = [1;2;3;4;5].
      Proof. reflexivity. Qed.
      Example test_app2: nil ++ [4;5] = [4;5].
      Proof. reflexivity. Qed.
      Example test_app3: [1;2;3] ++ nil = [1;2;3].
      Proof. reflexivity. Qed.
      

      Head與Tail

      下面介紹列表上的兩種運算:hd 函數返回列表的第一個元素(即“head”); tl 函數返回列表除去第一個元素以外的部分(即“tail”)。由于空表沒有表頭, 我們必須傳入一個參數作為返回的默認值。

      Definition hd (default:nat) (l:natlist) : nat :=
        match l with
        | nil ? default
        | h :: t ? h
        end.
      Definition tl (l:natlist) : natlist :=
        match l with
        | nil ? nil
        | h :: t ? t
        end.
      Example test_hd1: hd 0 [1;2;3] = 1.
      Proof. reflexivity. Qed.
      Example test_hd2: hd 0 [] = 0.
      Proof. reflexivity. Qed.
      Example test_tl: tl [1;2;3] = [2;3].
      Proof. reflexivity. Qed.
      

      用列表實現口袋(Bag)

      bag(或者叫 multiset 多重集)類似于集合,只是其中每個元素都能出現不止一次。 口袋的一種可行的表示是列表。

      Definition bag := natlist.
      

      有關列表的論證

      和數字一樣,有些列表處理函數的簡單事實僅通過化簡就能證明。

      Theorem nil_app : ? l:natlist,
        [] ++ l = l.
      Proof. reflexivity. Qed.
      

      ...由于 [] 被替換進了 app 定義中相應的“被檢”分支 (即經由匹配“仔細檢查”過值的表達式),整個匹配得以被簡化。

      和數字一樣,有時對一個列表做分類討論(是否是空)是非常有用的。

      Theorem tl_length_pred : ? l:natlist,
        pred (length l) = length (tl l).
      Proof.
        intros l. destruct l as [| n l'].
        - (* l = nil *)
          reflexivity.
        - (* l = cons n l' *)
          reflexivity. Qed.
      

      在這里 nil 的情況能夠工作是因為定義了 tl nil = nil, 而 destruct 策略中 as 注解引入的兩個名字,n 和 l',分別對應了 cons 構造子的兩個參數(正在構造的列表的頭和尾)。

      然而一般來說,許多關于列表的有趣定理都需要用到歸納法來證明。

      對列表進行歸納

      比起對自然數的歸納,歸納證明 natlist 這樣的數據類型更加陌生。 不過基本思路同樣簡單。每個 Inductive 聲明定義了一組數據值, 這些值可以用聲明過的構造子來構造。

      歸納定義的集合中元素的形式 '只能是' 構造子對其它項的應用。這一事實同時也給出了一種對歸納定義的集合進行論證的方法:一個自然數要么是 O,要么就是 S 應用到某個'更小'的自然數上;一個列表要么是 nil, 要么就是 cons 應用到某個數字和某個'更小'的列表上,諸如此類。

      • 首先,證明當 l 為 nil 時 P l 成立。

      • 然后,證明當 l 為 cons n l' 時 P l 成立,其中 n 是某個自然數,l' 是某個更小的列表,假設 P l' 成立.

      由于較大的列表總是能夠分解為較小的列表,最終這個較小的列表會變成 nil,這兩點合在一起就完成了 P 對一切列表 l 成立的證明。下面是個具體的例子:

      Theorem app_assoc : forall l1 l2 l3 : natlist,
        (l1 ++ l2) ++ l3 = l1 ++ (l2 ++ l3).
      Proof.
        intros l1 l2 l3. 
        induction l1 as [| n l1' IHl1'].
        - (* l1 = nil *)
          reflexivity.
        - (* l1 = cons n l1' *)
          simpl. 
          rewrite -> IHl1'. 
          reflexivity. 
      Qed.
      

      其使用自然語言描述為:

      '定理':對所有的列表 l1, l2, 和 l3, (l1 ++ l2) ++ l3 = l1 ++ (l2 ++ l3)。
      '證明': 通過對 l1 使用歸納法。

      首先, 假設 l1 = []。我們必須證明:
      $$([] ++ l2) ++ l3 = [] ++ (l2 ++ l3)$$

      這可以通過展開 ++ 的定義得到。

      然后, 假設 l1 = n::l1',有:
      $$(l1' ++ l2) ++ l3 = l1' ++ (l2 ++ l3)$$

      (歸納假設)。我們必須證明:
      $$((n :: l1') ++ l2) ++ l3 = (n :: l1') ++ (l2 ++ l3)$$

      根據 ++ 的定義, 上式等價于:
      $$n :: ((l1' ++ l2) ++ l3) = n :: (l1' ++ (l2 ++ l3))$$

      該式可通過我們的歸納假設立即證得。 ?

      反轉列表

      舉一個更加深入的例子來說明對列表的歸納證明:假設使用 app 來定義一個列表反轉函數 rev:

      Fixpoint rev (l:natlist) : natlist :=
        match l with
        | nil ? nil
        | h :: t ? rev t ++ [h]
        end.
      Example test_rev1: rev [1;2;3] = [3;2;1].
      Proof. reflexivity. Qed.
      Example test_rev2: rev nil = nil.
      Proof. reflexivity. Qed.
      

      為了比目前所見的證明多一點挑戰性, 來證明反轉一個列表不會改變它的長度。

      Theorem rev_length_firsttry : ? l : natlist,
        length (rev l) = length l.
      Proof.
        intros l. induction l as [| n l' IHl'].
        - (* l = nil *)
          reflexivity.
        - (* l = n :: l' *)
          (* 這種情況比較棘手。我們從一般的化簡開始。 *)
          simpl.
          (* 現在我們好像卡住了:目標是要證明涉及 ++ 的等式,
             但是我們在上下文和全局環境下并沒有任何有用的等式!
             通過用 IH 來重寫目標,我們可以推進一點... *)
          rewrite <- IHl'.
          (* ...但也僅此而已。 *)
      Abort.
      

      不妨單獨提出引理,闡述 ++ 與 length 形成的等式關系, 以從我們卡住的地方推進證明。

      Theorem app_length : ? l1 l2 : natlist,
        length (l1 ++ l2) = (length l1) + (length l2).
      Proof.
        (* 課上已完成 *)
        intros l1 l2. 
        induction l1 as [| n l1' IHl1'].
        - (* l1 = nil *)
          reflexivity.
        - (* l1 = cons *)
          simpl. 
          rewrite → IHl1'. 
          reflexivity. 
      Qed.
      

      現在可以完成最初的證明了。

      Theorem rev_length : ? l : natlist,
        length (rev l) = length l.
      Proof.
        intros l. induction l as [| n l' IHl'].
        - (* l = nil *)
          reflexivity.
        - (* l = cons *)
          simpl. 
          rewrite → app_length.
          simpl. 
          rewrite → IHl'. 
          rewrite plus_comm.
          reflexivity.
      Qed.
      

      '定理':對于所有 l,length (rev l) = length l。
      '證明':首先,觀察到 length (l ++ [n]) = S (length l) 對一切 l 成立, 這一點可通過對 l 的歸納直接得到。
      當 l = n'::l' 時,通過再次對 l 使用歸納, 然后同時使用之前觀察得到的性質和歸納假設即可證明。 ?

      Search 搜索

      我們已經見過很多需要使用之前證明過的結論(例如通過 rewrite)來證明的定理了。 但是在引用別的定理時,我們必須事先知道它們的名字。

      當然,即使是已被證明的定理本身 我們都不能全部記住,更不用提它們的名字了。

      Coq 的 Search 指令在這時就非常有用了。執行 Search foo 會讓 Coq 顯示所有涉及到 foo 的定理。

      例如,去掉下面的注釋后, 會看到一個我們證明過的所有關于 rev 的定理的列表:

      (*  Search rev. *)
      

      Options 可選類型

      假設我們想要寫一個返回某個列表中第 n 個元素的函數。如果我們為它賦予類型 nat → natlist → nat,那么當列表太短時我們仍須返回某個數...

      Fixpoint nth_bad (l:natlist) (n:nat) : nat :=
        match l with
        | nil ? 42
        | a :: l' ? match n with
          | 0 ? a
          | S n' ? nth_bad l' n'
          end
        end.
      

      這種方案并不好:如果 nth_bad 返回了 42,那么不經過進一步處理的話, 無法得知該值是否真的出現在了輸入中。

      因為無法判斷是什么因素讓它返回了 42.它可能是列表過短時的返回值,同時也可能是(此時列表足夠長)在列表中找到的值

      Inductive natoption : Type :=
        | Some (n : nat)
        | None.
      

      可以修改前面 nth_bad 的定義,使其在列表太短時返回 None, 在列表足夠長且 a 在 n 處時返回 Some a。將這個新函數稱為 nth_error 來表明它可以產生帶錯誤的結果。

      Fixpoint nth_error (l:natlist) (n:nat) : natoption :=
        match l with
        | nil ? None
        | a :: l' ? match n with
          | O ? Some a
          | S n' ? nth_error l' n'
          end
        end.
      Example test_nth_error1 : nth_error [4;5;6;7] 0 = Some 4.
      Example test_nth_error2 : nth_error [4;5;6;7] 3 = Some 7.
      Example test_nth_error3 : nth_error [4;5;6;7] 9 = None.
      

      Coq 的條件語句和其它語言中的一樣,不過加上了一點更為一般化的特性。

      由于 bool 類型不是內建的,因此 Coq 實際上支持在'Any'帶有兩個構造子的, 歸納定義的類型上使用條件表達式。

      當斷言(guard)求值為 Inductive 定義中的第一個構造子時,它被認為是真的;當它被求值到第二個構造子時, 則被認為是假的。

      Fixpoint nth_error' (l:natlist) (n:nat) : natoption :=
        match l with
        | nil ? None
        | a :: l' ? if n =? O then Some a
          else nth_error' l' (pred n)
        end.
      

      以下函數從 natoption 中取出一個 nat,在遇到 None 時它將返回提供的默認值。

      Definition option_elim (d : nat) (o : natoption) : nat :=
        match o with
        | Some n' ? n'
        | None ? d
        end.
      

      Partial Maps 偏映射

      下面的例子演示了如何在 Coq 中定義基礎的數據結構。這是一個簡單的 '偏映射' 數據類型,它類似于大多數編程語言中的映射或字典數據結構。

      首先,定義一個新的歸納數據類型 id 來用作偏映射的“鍵”。

      Inductive id : Type :=
        | Id (n : nat).
      

      本質上來說,id 只是一個數。但通過 Id 標簽封裝自然數來引入新的類型, 能讓定義變得更加可讀,同時也給了我們更多的靈活性。

      還需要一個 id 的相等關系測試:

      Definition eqb_id (x1 x2 : id) :=
        match x1, x2 with
        | Id n1, Id n2 ? n1 =? n2
        end.
      

      現在定義偏映射的類型:

      Inductive partial_map : Type :=
        | empty
        | record (i : id) (v : nat) (m : partial_map).
      

      此聲明可以理解為:“有兩種方式可以構造一個 partial_map:
      用構造子 empty 表示一個空的偏映射,
      或將構造子 record 應用到一個鍵、一個值和一個既有的 partial_map 來構造一個帶“鍵-值”映射 的 partial_map。”

      update 函數用于在部分映射中覆蓋給定的鍵以取締原值(如該鍵尚不存在, 則新建其記錄)。

      Definition update (d : partial_map)
        (x : id) (value : nat) : partial_map :=
        record x value d.
      

      最后,find 函數按照給定的鍵搜索一個 partial_map。若該鍵無法找到, 它就返回 None;若該鍵與 val 相關聯,則返回 Some val。 若同一個鍵被映到多個值,find 就會返回它遇到的第一個值。

      Fixpoint find (x : id) (d : partial_map) : natoption :=
        match d with
        | empty ? None
        | record y v d' ? if eqb_id x y
          then Some v
          else find x d'
        end.
      
      posted @ 2025-10-06 01:31  Mesonoxian  閱讀(10)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲欧美电影在线一区二区| 看黄a大片日本真人视频直播| 精品无码国产污污污免费| 7878成人国产在线观看| 日本精品不卡一二三区| 欧美性xxxxx极品少妇| 被黑人巨大一区二区三区| 蜜臀av一区二区国产在线| 亚洲国产午夜精品理论片在线播放 | 亚洲日韩性欧美中文字幕| 男女啪啪高清无遮挡免费| 国产精品自拍一二三四区| 亚洲性日韩精品一区二区| 亚洲男人天堂2018| 激情综合网激情国产av| 粉嫩少妇内射浓精videos| 日韩有码中文字幕国产| 国产又黄又爽又不遮挡视频| 欧美大胆老熟妇乱子伦视频| 永昌县| 四虎成人精品国产永久免费| 亚洲第一精品一二三区| 内射极品少妇xxxxxhd| 韩国主播av福利一区二区| 国产AV影片麻豆精品传媒| 天海翼激烈高潮到腰振不止| 男人的天堂av一二三区| 国产一区二区三区亚洲精品| 日韩精品av一区二区三区| 2020精品自拍视频曝光| 丰满高跟丝袜老熟女久久| 亚洲人成18在线看久| 成年女人片免费视频播放A| 亚洲精品tv久久久久久久久久| 亚洲码和欧洲码一二三四| 亚洲偷自拍国综合| 国产精品白浆免费视频| 精品国产线拍大陆久久尤物 | 国产亚洲av夜间福利香蕉149 | 国产精品中文字幕在线| 一二三四区无产乱码1000集 |