使编码槽位对七种构造闭合

可以直接阅读本章,也可以通过阅读指南和依赖地图选择其他路线。

阅读指南 · 依赖地图

L 内部,每条公式都被编码为载体的元素,且每条公式都有一个键:以元数数码居前、公式编码居后的有序对。某个界处的槽位收集一条公式及其全部子公式的键,因此槽位是一棵键树,而界只是相关引理的接口参数。本章证明槽位是闭合的:凡复合公式的键位于槽位中,其直接子公式的键也位于其中;这对带子公式的七种构造子逐一成立。

抽象的闭合原理在这里落实到具体对象:由公式语法树生成的诸键满足 closedAt。这正是沿这些键递归定义图时所需的闭合前提。

语言的构造子中有七个带子公式,其余三个不带,对后者无可闭合。七条子句各是四个动作:把槽位的成员求逆回「它是谁的键」的那条公式、从子句的标签算出那条公式的构造子、把部件的键放回复合公式自己的槽位、再把它们提升到整体的槽位。

本章围绕三个数学对象展开。元数为 j 的公式 χ 的键 keyʟ χ 是数码 jχ 的编码构成的有序对,而编码本身是编码模块的编码 LCode.⌜ χ 。槽位 slot B φ 是由这类键组成的集合,即 φ 及其整棵子公式树的键。closedAt 则陈述:一个槽位对七个构造子闭合,即合取、析取、蕴含、两个量词与两个有界量词。

{-# OPTIONS --cubical --safe --guardedness #-}

open import Base.Prelude
open import Base.Classical using ( LEM )

module L.Coding.SlotClosure { : Level} (lem : LEM (ℓ-suc )) where

公式即对象语言的公式,其满足在可构造结构中读取:下文的满足符号一律指那里的满足。外围层级提供键与槽位所由构成的底层元素。

open import FOL.ZFStructure using ( module hPropStructure )
open import FOL.Syntax
  using ( Term; Formula; _∧̇_; _∨̇_; _⇒̇_; ∃̇_; ∀̇_; ∀̇∈; ∃̇∈ )
import FOL.Absoluteness
open import V.Hierarchy {} using ( 𝒮ᵥ )

有序对编码键,且分量可恢复,因此一个键可以拆开为元数分量与编码分量。可构造结构承载诸编码;编码模块定义公式的编码 ⌜_⌝ 与码上的配对运算;闭包模块则逐形状陈述七条闭合子句及其引入形式。

open import V.Coding {} using ( pr; pr-inj )
open import L.Constructible {} using ( 𝒮ʟ; isL; isL-trans )
open import L.Coding.Model {} using ( module LCode; prʟ; prʟ-fst )
open import L.Coding.Closure {} using ( closedAt; binSameClosed-in; unSameClosed-in; unSuccClosed-in; binSuccClosed-in; binShapeAt; unShapeAt; bothSameAt; oneSameAt; oneSuccAt; succSndAt )

满足表一章是三个核心对象的出处。它定义了公式的键 keyʟ、按构造子标签分解公式的形状引理 keyʟ-shape、挂在公式与某个界上的槽位 slot、把槽位成员求逆回其键所属公式的 slot-inv,以及关于键树的部件引理 Parts

open import L.Axioms.Numerals {} using ( numeralL; numeralL-fst )
open import L.Coding.SatisfactionTable {} lem
  using ( keyʟ; keyʟ-shape; slot; satTable; slot-inv; module Parts )

槽位成员只能在命题截断下求逆,因此每条子句都把该截断消去到一个命题。保持元数的二元情形以两个隶属命题的合取为目标;一元情形与有界情形的目标则各是一个隶属命题。

import Cubical.HITs.PropositionalTruncation as PT
open import Cubical.Foundations.HLevels using ( isProp× )
open import Cubical.HITs.CumulativeHierarchy.Base using ( V; _∈_ )
open import Cubical.HITs.CumulativeHierarchy.Constructions
  using ( module InfinitySet )

元数以数码记录,而抬升元数的构造子记录的是数码的后继;二者都取自外围的无穷集合。

open InfinitySet using ( #_; sucV )

可构造结构的载体是本章一切码、键与槽位所居的类型。

open hPropStructure 𝒮ʟ

这里的 S ^ n 表示长度为 n 的环境向量;重命名为 _⊨_ 的关系,则是在这种环境下读取限制可构造结构中的满足。

module AbsL = FOL.Absoluteness.Single 𝒮ᵥ isL isL-trans
open AbsL using ( _^_ ) renaming ( _⊨ᵐ_ to _⊨_ )

把部件的键放回去

键树由部件引理支配。Parts.self 说公式自己的键在自己的槽位中;Parts.leftParts.rightParts.only 说复合公式的槽位包含其直接部件槽位中的键:这是沿构造子树的子树包含,由部件引理与求逆给出,从不来自界的任何序或向下的闭合。界 B 在其中只是作为接口参数传递。于是闭合子句所需做的,是把子句所读的对认作某个部件的键;下面两条引理恰完成此事。

module _ (B : S) where
  private
    Sl :  {n}  Formula S n  S
    Sl = slot B

键的计算,就元数为 j 的公式 χ 陈述:凡第一分量为元数数码 # j第二分量⌜ χ 的编码分量的对,都等于键 fst (keyʟ χ)。注意三个量互不相同:⌜ χ 是公式的编码,其第一分量才是进入键的那个量,而键是数码居前的有序对。

  key≡ :  {j} (χ : Formula S j) (ar p : V )  # j  ar
        p  fst LCode.⌜ χ   pr ar p  fst (keyʟ χ)

两条假设都必须用到:元数等式与编码分量等式。证明是穿过两条计算法则的短链:j 的数码的第一分量# j,而编码对的第一分量第一分量的对。

  key≡ {j} χ ar p qa qp =
      cong₂ pr (sym qa) qp
     cong  w  pr w (fst LCode.⌜ χ )) (sym (numeralL-fst j))
     sym (prʟ-fst (numeralL j) LCode.⌜ χ )

抬升形式对元数为 suc j 的公式 χ 陈述同一事实:此时键的第一分量是元数数码的后继,而这恰是构造子抬升元数时子句所读取的量。

  keyS≡ :  {j} (χ : Formula S (suc j)) (ar p : V )  # j  ar
         p  fst LCode.⌜ χ   pr (sucV ar) p  fst (keyʟ χ)

链是同一条,只是把后继沿元数等式推过去:suc j 的数码的第一分量suc (# j),而子句的抬升读法与之相合。

  keyS≡ {j} χ ar p qa qp =
      cong₂ pr (cong sucV (sym qa)) qp
     cong  w  pr w (fst LCode.⌜ χ )) (sym (numeralL-fst (suc j)))
     sym (prʟ-fst (numeralL (suc j)) LCode.⌜ χ )

七条子句

子句按各构造子所要求的闭合形状组织。共证明四个主体,每种形状一个:保持元数的二元构造子、保持元数的一元构造子、抬升元数的一元构造子、把项与抬升元数公式配对的二元构造子。同一主体下两条子句的不同只在构造子的标签与其交还的部件,而两者都是参数。每条子句经四个动作运行:把槽位成员求逆成一条公式、按标签读出其构造子、把部件的键放回该公式自己的槽位、再提升到整体的槽位。

  module _ {n : } (φ : Formula S n) {k : } (γ : S ^ k) where
    private
      δ : S ^ (suc (suc (suc k)))
      δ = B  satTable B φ  Sl φ  γ

被证明闭合的递归以固定公式 φ 的槽位为索引,其环境携带三个具名条目:界、φ 处的满足表,以及该槽位。环境的其余槽位留给具体实例。

      Ci : Fin (suc (suc (suc k)))
      Ci = suc (suc zero)

位置 Ci 是槽位在此环境中的索引;每条子句都恰在这个位置读取槽位。

    binSame : (k' : ) (op :  {m}  Formula S m  Formula S m  Formula S m)
             (∀ {m} (ψ : Formula S m)  LCode.Match k' ψ
                Σ[ a'  Formula S m ] (Σ[ b'  Formula S m ] (ψ  op a' b')))
             (∀ {m} (a' b' : Formula S m)
                LCode.payOf (op a' b')  prʟ LCode.⌜ a'  LCode.⌜ b' )

第一个主体覆盖保持元数的二元构造子,即合取、析取、蕴含的形状。其假设描述标签 k':一条公式与该标签匹配,当且仅当它由同元数的两条公式 op a' b' 构成,且这种复合的载荷是两个部件编码构成的有序对。

             (∀ {m} (a' b' : Formula S m) (z : V )
                 z  fst (Sl a')    z  fst (Sl (op a' b')) )
             (∀ {m} (a' b' : Formula S m) (z : V )
                 z  fst (Sl b')    z  fst (Sl (op a' b')) )
              δ  binShapeAt Ci k' (bothSameAt Ci) 

两条闭合方向分别是部件引理给出的左、右子树包含;结论即子句自身:槽位对标签 k' 以「交还两个部件的键」的形状闭合。

    binSame k' op get payOp inL inR = binSameClosed-in Ci k' δ
       c ar a b c∈ sh  PT.rec
        (isProp× (snd (pr (fst ar) (fst a)  fst (Sl φ)))
                 (snd (pr (fst ar) (fst b)  fst (Sl φ))))
         { (m , ψ , (q , incl)) 

第一步对槽位成员 c 求逆。它仅仅地是某条元数为 m 的公式 ψ 的键,求逆同时返回该键属于 φ 的槽位。目标是两个隶属的合取,由 isProp× 是命题,这使截断消去合法。

          let r  = keyʟ-shape ψ k' (fst ar) (pr (fst a) (fst b)) (sym q  sh)
              g  = get ψ (r .fst)
              a' = g .fst
              b' = g .snd .fst
               = g .snd .snd

第二步计算构造子。形状引理以子句的形状证明把 ψ 对上标签 k',随同匹配返回元数等式与载荷等式;分解假设进而把 ψ 写成两个直接子公式的 op a' b'

              pay = sym (prʟ-fst LCode.⌜ a'  LCode.⌜ b' )
                   cong fst (sym (payOp a' b'))
                   cong  w  fst (LCode.payOf w)) (sym )  r .snd .snd

第三步是关于载荷的共享计算。成员 c 是键形的对,其载荷分量记录着两个部件的编码分量;链条证明这些被记录的分量按分量分别是编码 ⌜ a' ⌜ b' :由构造子自身的载荷法则,ψ 的载荷是两个部件编码构成的对,而形状引理的载荷等式把它与从 c 读出的对连接起来。此处切莫混淆三个量:整条公式的编码 ⌜ ψ 、位于其中的载荷分量,以及第一槽携带元数的最终的键。

              inψ : (χ : Formula S m)   fst (keyʟ χ)  fst (Sl ψ) 
                    fst (keyʟ χ)  fst (Sl φ) 
              inψ χ h = incl (fst (keyʟ χ)) h
          in subst  w   w  fst (Sl φ) )
               (sym (key≡ a' (fst ar) (fst a) (r .snd .fst) (sym (pr-inj pay .fst))))

第四个动作把键送回。先由辅助函数借求逆返回的包含,把任一同元数公式的键从其槽位提升到 φ 的槽位;再由形状引理的元数等式与编码单射性供给的第一分量等式喂给 key≡,把子句所读对的隶属改写为 a' 的键的隶属。

               (inψ a' (subst  w   fst (keyʟ a')  fst (Sl w) ) (sym )
                 (inL a' b' _ (Parts.self B keyʟ a'))))
           , subst  w   w  fst (Sl φ) )
               (sym (key≡ b' (fst ar) (fst b) (r .snd .fst) (sym (pr-inj pay .snd))))

右分量以右侧闭合方向与单射性供给的第二分量等式重复同一组装,改写为含 b' 那个对的隶属。两半合拢,子句证毕。

               (inψ b' (subst  w   fst (keyʟ b')  fst (Sl w) ) (sym )
                 (inR a' b' _ (Parts.self B keyʟ b')))) })
        (slot-inv B φ (fst c) c∈))

消去由求逆供给,那条包含正是从那里来的。两侧分量组装完毕,子句即告证成。

    andC :  δ  binShapeAt Ci 2 (bothSameAt Ci) 
    andC = binSame 2 _∧̇_  _ m  m)  _ _  refl)
              a' b'  Parts.left B keyʟ (a' ∧̇ b') a' b')
              a' b'  Parts.right B keyʟ (a' ∧̇ b') a' b')

合取是第一个实例:a' ∧̇ b' 的槽位包含两个合取支槽位的键。

    orC :  δ  binShapeAt Ci 3 (bothSameAt Ci) 
    orC = binSame 3 _∨̇_  _ m  m)  _ _  refl)
             a' b'  Parts.left B keyʟ (a' ∨̇ b') a' b')
             a' b'  Parts.right B keyʟ (a' ∨̇ b') a' b')

析取是形状相同的第二个实例,带自己的标签与自己的部件引理。

    impC :  δ  binShapeAt Ci 4 (bothSameAt Ci) 
    impC = binSame 4 _⇒̇_  _ m  m)  _ _  refl)
              a' b'  Parts.left B keyʟ (a' ⇒̇ b') a' b')
              a' b'  Parts.right B keyʟ (a' ⇒̇ b') a' b')

蕴含是第三个:a' ⇒̇ b' 的槽位包含前件槽位的键与后件槽位的键,子句由同样四个动作证得。

    unSame : (k' : ) (op :  {m}  Formula S m  Formula S m)
            (∀ {m} (ψ : Formula S m)  LCode.Match k' ψ
               Σ[ a'  Formula S m ] (ψ  op a'))
            (∀ {m} (a' : Formula S m)  LCode.payOf (op a')  LCode.⌜ a' )

辅助引理 unSame 证明了一个假想的、保持元数的一元运算所满足的相应闭合原理。本语言的十个构造子都不具有这种形状,因此 closedAt 不使用这一辅助引理。

            (∀ {m} (a' : Formula S m) (z : V )
                z  fst (Sl a')    z  fst (Sl (op a')) )
             δ  unShapeAt Ci k' (oneSameAt Ci) 

闭合方向与结论都是单部件形状:被要求交还的只有那唯一子公式的键。

    unSame k' op get payOp inA = unSameClosed-in Ci k' δ
       c ar a c∈ sh  PT.rec (snd (pr (fst ar) (fst a)  fst (Sl φ)))
         { (m , ψ , (q , incl)) 
          let r  = keyʟ-shape ψ k' (fst ar) (fst a) (sym q  sh)
              g  = get ψ (r .fst)

证明以一个分量运行同样的四个动作。求逆产出 ψ 及其到 φ 槽位的包含,形状引理按标签分解它,而此处的读取只涉及元数与那唯一的编码。

              a' = g .fst
               = g .snd
              pay = cong fst (sym (payOp a'))
                   cong  w  fst (LCode.payOf w)) (sym )  r .snd .snd
          in subst  w   w  fst (Sl φ) )

这里的共享计算更短:op a' 的载荷就是 a' 自己的编码,故链条把成员 c 中记录的编码分量直接认同为 a' 的编码分量,无须拆分任何对。

               (sym (key≡ a' (fst ar) (fst a) (r .snd .fst) (sym pay)))
               (incl (fst (keyʟ a'))
                 (subst  w   fst (keyʟ a')  fst (Sl w) ) (sym )
                   (inA a' _ (Parts.self B keyʟ a')))) })
        (slot-inv B φ (fst c) c∈))

第四个动作一次性组装该情形:a' 的键在自己的槽位中,inA 把它移入 op a' 的槽位,incl 提升到 φ 的槽位,key≡ 完成改写,元数等式包含在内。

    unSucc : (k' : ) (op :  {m}  Formula S (suc m)  Formula S m)
            (∀ {m} (ψ : Formula S m)  LCode.Match k' ψ
               Σ[ a'  Formula S (suc m) ] (ψ  op a'))
            (∀ {m} (a' : Formula S (suc m))  LCode.payOf (op a')  LCode.⌜ a' )
            (∀ {m} (a' : Formula S (suc m)) (z : V )

第三个主体覆盖抬升元数的一元构造子,即两个量词的形状。其假设是抬升版本:标签恰与由抬升元数公式经 op 构成的公式匹配,载荷就是该公式自己的编码,且唯一一条闭合方向把它的键送入复合槽位。

                z  fst (Sl a')    z  fst (Sl (op a')) )
             δ  unShapeAt Ci k' (oneSuccAt Ci) 

读取与结论使用抬升形式:子句读取的对以元数数码的后继居首,并要求子公式的键以单部件形状交还。

    unSucc k' op get payOp inA = unSuccClosed-in Ci k' δ
       c ar a c∈ sh  PT.rec (snd (pr (sucV (fst ar)) (fst a)  fst (Sl φ)))
         { (m , ψ , (q , incl)) 
          let r  = keyʟ-shape ψ k' (fst ar) (fst a) (sym q  sh)
              g  = get ψ (r .fst)

前两个动作照旧:把成员求逆成公式,再按标签分解出唯一的、元数抬升的子公式。

              a' = g .fst
               = g .snd
              pay = cong fst (sym (payOp a'))
                   cong  w  fst (LCode.payOf w)) (sym )  r .snd .snd
          in subst  w   w  fst (Sl φ) )

载荷计算把被记录的编码分量认同为子公式的编码。另一方面,形状等式给出 # m ≡ fst ar;只有 keyS≡ 对该等式施加 sucV 时,后继才被引入。

               (sym (keyS≡ a' (fst ar) (fst a) (r .snd .fst) (sym pay)))
               (incl (fst (keyʟ a'))
                 (subst  w   fst (keyʟ a')  fst (Sl w) ) (sym )
                   (inA a' _ (Parts.self B keyʟ a')))) })
        (slot-inv B φ (fst c) c∈))

改写经由 keyS≡ 完成:它对 # m ≡ fst ar 施加 sucV,再与编码分量等式合并,从而把子句所读的对认同为 a' 的键。

    binSucc : (k' : )
             (op :  {m}  Term S m  Formula S (suc m)  Formula S m)
             (∀ {m} (ψ : Formula S m)  LCode.Match k' ψ
                Σ[ t  Term S m ] (Σ[ a'  Formula S (suc m) ] (ψ  op t a')))
             (∀ {m} (t : Term S m) (a' : Formula S (suc m))

第四个主体覆盖有界量词,其构造子把一个项与一个元数抬升的公式配对。这种复合的载荷按次序编码项与子公式,而只有子公式本身是公式,故被要求交回的只有它的键。

                LCode.payOf (op t a')  prʟ LCode.⌜ t ⌝ᵗ LCode.⌜ a' )
             (∀ {m} (t : Term S m) (a' : Formula S (suc m)) (z : V )
                 z  fst (Sl a')    z  fst (Sl (op t a')) )
              δ  binShapeAt Ci k' (succSndAt Ci) 

结论是第二分量形状:子句读取的对以抬升的元数居前、公式的编码分量居后,并要求交回子公式的键。

    binSucc k' op get payOp inA = binSuccClosed-in Ci k' δ
       c ar a b c∈ sh  PT.rec (snd (pr (sucV (fst ar)) (fst b)  fst (Sl φ)))
         { (m , ψ , (q , incl)) 
          let r  = keyʟ-shape ψ k' (fst ar) (pr (fst a) (fst b)) (sym q  sh)
              g  = get ψ (r .fst)

成员 c 是键形的对,其载荷携带两个分量:居前的项 t 的编码分量,与居后的子公式 a' 的编码分量。子句读取的是抬升元数连同第二分量

              t  = g .fst
              a' = g .snd .fst
               = g .snd .snd
              pay = sym (prʟ-fst LCode.⌜ t ⌝ᵗ LCode.⌜ a' )
                   cong fst (sym (payOp t a'))

共享计算把成员中记录的载荷按分量认同为 ⌜ t ⌝ᵗ⌜ a' 的编码对。改写所消耗的是由编码单射性供给的第二分量等式;项乘坐在第一分量里,随后退出。

                   cong  w  fst (LCode.payOf w)) (sym )  r .snd .snd
          in subst  w   w  fst (Sl φ) )
               (sym (keyS≡ a' (fst ar) (fst b) (r .snd .fst)
                 (sym (pr-inj pay .snd))))
               (incl (fst (keyʟ a'))

keyS≡ 的改写使用元数等式与第二分量等式,落定为子句所读对的隶属。第四个动作随后把 a' 的键经它自己的槽位与闭合方向提升到 φ 的槽位,而求逆供给那条包含。

                 (subst  w   fst (keyʟ a')  fst (Sl w) ) (sym )
                   (inA t a' _ (Parts.self B keyʟ a')))) })
        (slot-inv B φ (fst c) c∈))

两个量词例示第三个主体。各自供给标签、分解、定义性成立的载荷等式,以及唯一一条闭合方向:∃̇ a' 的槽位包含 a' 槽位的键,全称量词亦然。

    exC :  δ  unShapeAt Ci 6 (oneSuccAt Ci) 
    exC = unSucc 6 ∃̇_  _ m  m)  _  refl)
             a'  Parts.only B keyʟ (∃̇ a') a')

全称量词是同一主体的第二个实例,带标签七与自己的部件引理。

    allC :  δ  unShapeAt Ci 7 (oneSuccAt Ci) 
    allC = unSucc 7 ∀̇_  _ m  m)  _  refl)
              a'  Parts.only B keyʟ (∀̇ a') a')

两个有界量词以标签八与九例示第四个主体:∀̇∈ t a' 的槽位包含 a' 槽位的键,存在有界量词亦然。

    allInC :  δ  binShapeAt Ci 8 (succSndAt Ci) 
    allInC = binSucc 8 ∀̇∈  _ m  m)  _ _  refl)
                t a'  Parts.only B keyʟ (∀̇∈ t a') a')

存在有界量词是七条子句中的最后一条。

    exInC :  δ  binShapeAt Ci 9 (succSndAt Ci) 
    exInC = binSucc 9 ∃̇∈  _ m  m)  _ _  refl)
               t a'  Parts.only B keyʟ (∃̇∈ t a') a')

七条子句组装成闭合陈述 closedAtφ 在该界处的槽位对每个带子公式的构造子闭合。这就消解了对编码的递归对其索引集陈述的假设;也正因如此,这样的递归才能在每个复合码处求助于直接子公式键处记录的取值。本章的三个对象各尽其用:键识别了子句所读的对,槽位树供给了闭合方向,closedAt 汇集了结果。

    slotClosed :  δ  closedAt Ci 
    slotClosed = andC , (orC , (impC
               , (exC , (allC , (allInC , exInC)))))