---
title: "非直谓性"
module: Base.Impredicativity
lang: zh
site: "Bedrock"
description: "非直谓性"
stage: "基础"
reading_order: 3
canonical: https://bedrock.institute/zh/Base.Impredicativity.html
html: Base.Impredicativity.html
agda_source: https://github.com/BedrockInstitute/Bedrock/blob/main/src/Base/Impredicativity.lagda.md
prerequisites: [Base.Prelude]
routes: [common-foundations]
translations: [https://bedrock.institute/en/Base.Impredicativity.md, https://bedrock.institute/ja/Base.Impredicativity.md]
agent_guide: https://bedrock.institute/llms.txt
license: "CC-BY-NC-SA-4.0"
---


```agda
{-# OPTIONS --cubical --safe --guardedness #-}
module Base.Impredicativity where
```

# 非直谓性

```agda
open import Base.Prelude
```

直谓主义数学基础不允许在一个定义中量化某个已经包含待定义对象的总体。Cubical Agda 建立在这样的基础之上，而本书所要形式化的集合论包含非直谓的构造。为了在直谓式的宿主中准确说明这些构造需要什么，本章专门提出一组接口：它们不改变宿主本身，而是把开展非直谓数学所需的额外条件明确列为假设。

直谓主义数学基础可以容纳这样的非直谓假设，正如直觉主义逻辑可以明确加入经典逻辑原理；反过来却不成立，因为一旦基础本身预先采用了更强的原则，就无法再分辨后续结果究竟依赖哪些额外假设。因此，本书保留 Cubical Agda 的直谓式基础，并在需要非直谓性时，通过本章的接口逐项说明所用的条件。

困难来自宇宙层级。底层类型位于 `Type ℓ` 的所有命题组成 `hProp ℓ`，而这个命题宇宙整体属于 `Type (ℓ-suc ℓ)`。因此，对 `hProp ℓ` 中所有命题量化所得的命题，不一定仍能放在层级 `ℓ`。

例如，试图把命题 `R` 定义为「每个 `Q : hProp ℓ` 都蕴含自身」，同时要求 `R` 也属于 `hProp ℓ`。这样，定义中的「每个 `Q`」也遍及 `R`：量化的总体已经包含正在定义的命题。「`Q` 蕴含自身」虽然显然成立，难点仍是要求这次量化所得的命题留在同一层级。在 Cubical Agda 中，它位于高一层的宇宙。Agda 的用户代码不能改写其宇宙层级规则，但可以通过显式假设，把这个高层命题与真值内容相同的低层代表联系起来。

我们用基础词汇中介绍的类型等价 `A ≃ B` 表达这种联系。它允许两个类型位于不同宇宙，同时保留其中的元素与路径。接下来要区分两种尺寸要求：逐个为命题寻找代表，以及用一个类型呈现整个命题宇宙。

## 命题换级

给定 `P : hProp ℓ₁`，Agda 不允许我们直接改变 `P` 所在的层级；能够提出的要求，是在目标层级找到另一个命题 `Q : hProp ℓ₂`，使二者的底层类型类型等价。

**定义** (`hasSize`) 我们把「`P` 具有尺寸 `ℓ₂`」记作 `hasSize ℓ₂ P`，并将其定义为以下依值对：第一分量选出 `Q`，第二分量给出类型等价，表明 `Q` 与 `P` 具有完全相同的真值内容。

```agda
hasSize : ∀ {ℓ₁} (ℓ₂ : Level) → hProp ℓ₁ → Type (ℓ-max ℓ₁ (ℓ-suc ℓ₂))
hasSize ℓ₂ P = Σ[ Q ∶ hProp ℓ₂ ] (⟨ P ⟩ ≃ ⟨ Q ⟩)
```

这里不要求两个层级有大小顺序。在后面的应用中，`ℓ₁` 通常是模型真值所在的层级，`ℓ₂` 是索引所在的层级；但定义本身允许任意两个层级。「命题换级」是指用目标层级中的类型等价代表替换原命题，而不是修改原命题的宇宙标注。

**定义** (`Resizing`) 我们把「`ℓ₁` 层的命题可换级到 `ℓ₂` 层」记作 `Resizing ℓ₁ ℓ₂`，并将其定义为以下依值函数：对每个 `P : hProp ℓ₁`，它返回「`P` 具有尺寸 `ℓ₂`」的见证。

```agda
Resizing : ∀ ℓ₁ ℓ₂ → Type (ℓ-max (ℓ-suc ℓ₁) (ℓ-suc ℓ₂))
Resizing ℓ₁ ℓ₂ = (P : hProp ℓ₁) → hasSize ℓ₂ P
```

## 命题宇宙换级

**定义** (`ΩResizing`) 我们把「命题宇宙 `hProp ℓ₁` 具有尺寸 `ℓ₂`」记作 `ΩResizing ℓ₁ ℓ₂`，并将其定义为以下依值对：第一分量给出类型 `Ω : Type ℓ₂`，第二分量给出类型等价 `hProp ℓ₁ ≃ Ω`。因此，`ℓ₁` 层的每个命题都在 `Ω` 中有编码，而 `Ω` 的每个元素也都解码为该层的命题。

```agda
ΩResizing : ∀ ℓ₁ ℓ₂ → Type (ℓ-max (ℓ-suc ℓ₁) (ℓ-suc ℓ₂))
ΩResizing ℓ₁ ℓ₂ = Σ[ Ω ∶ Type ℓ₂ ] (hProp ℓ₁ ≃ Ω)
```

<figure class="book-diagram type-comparison resizing-comparison" id="fig-resizing-comparison" aria-describedby="fig-resizing-comparison-caption">
<section class="diagram-panel resizing-case">

<p class="type-comparison-title"><strong>命题换级</strong></p>

<p class="resizing-note">命题换级为每个命题在指定宇宙层级选取一个类型等价的代表。</p>

$$r : \operatorname{Resizing}\,\ell_1\,\ell_2$$

<div class="resizing-scene">
<div class="resizing-label">

$$P_i : \operatorname{hProp}\,\ell_1$$

</div>
<div></div>
<div class="resizing-label">

$$Q_i : \operatorname{hProp}\,\ell_2$$

</div>
<div class="diagram-space resizing-type">

$$\langle P_1\rangle$$

</div>
<div class="resizing-bridge">

$$\overset{e_1}{\simeq}$$

</div>
<div class="diagram-space resizing-type">

$$\langle Q_1\rangle$$

</div>
<div class="diagram-space resizing-type">

$$\langle P_2\rangle$$

</div>
<div class="resizing-bridge">

$$\overset{e_2}{\simeq}$$

</div>
<div class="diagram-space resizing-type">

$$\langle Q_2\rangle$$

</div>
<div class="resizing-label">

$$\vdots$$

</div>
<div></div>
<div class="resizing-label">

$$\vdots$$

</div>
</div>

$$r(P_i) = (Q_i,e_i)$$

</section>
<section class="diagram-panel resizing-case">

<p class="type-comparison-title"><strong>命题宇宙换级</strong></p>

<p class="resizing-note">命题宇宙换级用指定宇宙层级中的一个类型呈现整个命题宇宙。</p>

$$(\Omega,e) : \Omega\operatorname{Resizing}\,\ell_1\,\ell_2$$

<div class="resizing-scene resizing-whole">
<div class="diagram-space resizing-universe">

$$\operatorname{hProp}\,\ell_1$$

<div class="resizing-points">
<div class="resizing-point">

$$P_1$$

</div>
<div class="resizing-point">

$$P_2$$

</div>
<div class="resizing-point">

$$\cdots$$

</div>
</div>
</div>
<div class="resizing-bridge">

$$\overset{e}{\simeq}$$

</div>
<div class="diagram-space resizing-universe">

$$\Omega : \operatorname{Type}_{\ell_2}$$

<div class="resizing-points">
<div class="resizing-point">

$$c_1$$

</div>
<div class="resizing-point">

$$c_2$$

</div>
<div class="resizing-point">

$$\cdots$$

</div>
</div>
</div>
</div>

$$c_i = \operatorname{equivFun}\,e\,P_i : \Omega$$

</section>
<figcaption id="fig-resizing-comparison-caption">

逐个命题换级与整个命题宇宙换级，要求的是不同的数据

</figcaption>
</figure>

接下来证明：命题宇宙换级蕴含命题换级。假设给定 `Ω : Type ℓ₂` 和等价 `e : hProp ℓ₁ ≃ Ω`。等价使每个命题都有 `Ω` 中的编码；我们还需要从这个编码构造 `ℓ₂` 层的命题，并证明它与原命题等价。

通常的数学证明会先说「以下固定 `Ω` 和 `e`」，再在这两个共同前提下完成一系列构造。Agda 用带参数的子模块 `CodedTruth` 表达同样的安排：模块声明列出共同前提，里面的定义都可以直接使用它们，不必反复写出参数。证明最后收到具体的 `(Ω , e)` 时，再取用这一组构造。`private` 只表示这个模块是本章内部的辅助工具，并未增加数学假设。

<details open class="submodule-fold">
<summary class="submodule-fold-heading">

```agda
private module CodedTruth {ℓ₁ ℓ₂} (Ω : Type ℓ₂) (e : hProp ℓ₁ ≃ Ω) where
```

</summary>
<div class="submodule-fold-content">

把 `e` 的正向映射命名为 `c`。于是 `c P` 是 `P` 在 `Ω` 中的编码。

```agda
  c : hProp ℓ₁ → Ω
  c = equivFun e
```

**构造** (`codedTruth`) 编码 `c P` 是 `Ω` 中的一个点。要得到命题，就问它是否等于真命题的编码：`c ⊤ ≡ c P`。这个路径类型位于 `ℓ₂` 层；`e` 把 `hProp ℓ₁` 的 h-集合结构搬运到 `Ω`，保证它是命题。我们取它作为 `P` 的代表，下面的同构将证明二者具有相同的真值内容。

```agda
  codedTruth : hProp ℓ₁ → hProp ℓ₂
  codedTruth P = (c ⊤ ≡ c P) , isOfHLevelRespectEquiv 2 e isSetHProp _ _
```

`Ω` 中的带状区域示意端点为 `c(⊤)`、`c(P)` 的路径族。点击它，路径族展开成第二个类型空间，整条路径改画成其中的点。图中的 `q`、`r` 以 `P` 有证明为前提；与 `⟨ P ⟩` 的类型等价本身不需要这个假设。

<figure class="book-diagram type-comparison path-figure" id="fig-coded-truth" aria-describedby="fig-coded-truth-caption">
<div class="coded-truth-proof-scene">
<div class="diagram-space coded-truth-proof">

$$\langle P\rangle$$

<div class="coded-truth-universe">

$$: \operatorname{Type}_{\ell_1}$$

</div>
<div class="path-stage" style="aspect-ratio:200/140">
<svg viewBox="0 0 200 140" aria-hidden="true" focusable="false">
<circle class="diagram-point" cx="100" cy="70" r="4"/>
</svg>
<span class="path-label" style="left:50%;top:75%">$p$</span>
</div>
</div>
<div class="coded-truth-equivalence">$\simeq$</div>
<div class="diagram-space coded-truth-proof coded-truth-proof-target">

$$\langle\operatorname{codedTruth}\,P\rangle$$

<div class="coded-truth-universe">

$$: \operatorname{Type}_{\ell_2}$$

</div>
<div class="path-stage" style="aspect-ratio:200/140">
<svg viewBox="0 0 200 140" aria-hidden="true" focusable="false">
<circle class="diagram-point coded-truth-target coded-truth-target-q" cx="65" cy="70" r="4"/>
<circle class="diagram-point coded-truth-target coded-truth-target-r" cx="135" cy="70" r="4"/>
</svg>
<span class="path-label coded-truth-target" style="left:32.5%;top:75%">$q$</span>
<span class="path-label coded-truth-target" style="left:67.5%;top:75%">$r$</span>
</div>
</div>
<div class="coded-truth-detail-link">
<svg class="coded-truth-detail-horizontal" viewBox="0 0 90 30" aria-hidden="true" focusable="false">
<path class="diagram-guide" d="M0 15 L90 15"/>
</svg>
<svg class="coded-truth-detail-vertical" viewBox="0 0 30 50" aria-hidden="true" focusable="false">
<path class="diagram-guide" d="M15 0 L15 50"/>
</svg>
</div>
<div class="diagram-space coded-truth-expanded">

$$\Omega$$

<div class="coded-truth-universe">

$$: \operatorname{Type}_{\ell_2}$$

</div>
<div class="path-stage coded-truth-trigger" style="aspect-ratio:410/200">
<svg viewBox="0 0 410 200" aria-hidden="true" focusable="false">
<path class="diagram-path-space coded-truth-source-region" d="M100 95 Q205 0 310 95 Q205 190 100 95 Z"/>
<path class="diagram-path" d="M100 95 Q205 0 310 95"/>
<path class="diagram-path" d="M100 95 Q205 190 310 95"/>
<circle class="diagram-point" cx="100" cy="95" r="4"/>
<circle class="diagram-point" cx="310" cy="95" r="4"/>
<g class="coded-truth-moving-space">
<path class="diagram-path-space coded-truth-region-copy" d="M100 95 Q205 0 310 95 Q205 190 100 95 Z"/>
<g class="coded-truth-path-copy-q">
<path class="diagram-path" d="M100 95 Q205 0 310 95"/>
<circle class="diagram-point" cx="100" cy="95" r="4"/>
<circle class="diagram-point" cx="310" cy="95" r="4"/>
</g>
<g class="coded-truth-path-copy-r">
<path class="diagram-path" d="M100 95 Q205 190 310 95"/>
<circle class="diagram-point" cx="100" cy="95" r="4"/>
<circle class="diagram-point" cx="310" cy="95" r="4"/>
</g>
</g>
</svg>
<span class="path-label" style="left:50%;top:10%">$q$</span>
<span class="path-label coded-truth-region-label" style="left:50%;top:47.5%">$\langle\operatorname{codedTruth}\,P\rangle$</span>
<span class="path-label" style="left:50%;top:81%">$r$</span>
<span class="path-label" style="left:10.98%;top:47.5%">$c(\top)$</span>
<span class="path-label" style="left:89.02%;top:47.5%">$c(P)$</span>
</div>
</div>
</div>
<figcaption id="fig-coded-truth-caption">

`⟨ codedTruth P ⟩` 中的一个点，就是 `Ω` 中的一整条路径：`⟨ codedTruth P ⟩ = (c(⊤) ≡ c(P))`。两个证明类型分别位于 `ℓ₁` 和 `ℓ₂` 层，彼此类型等价

</figcaption>
</figure>

**引理** (`codedTruthIso`) `P` 的底层类型与 `codedTruth P` 的底层类型同构。因此，上面构造的代表确实与 `P` 具有相同的真值内容。

```agda
  codedTruthIso : (P : hProp ℓ₁) → Iso ⟨ P ⟩ ⟨ codedTruth P ⟩
```

**证明** 我们构造两个方向的映射 `to` 和 `from`，再用 `iso` 把它们组装起来。源 `⟨ P ⟩` 和目标 `⟨ codedTruth P ⟩` 都是命题，因此给出两个映射之后，两端的命题性便可直接证明两条往返律。映射需要返回真命题的元素时，我们显式写出其唯一元素 `tt*`。

```agda
  codedTruthIso P = iso to from (λ q → ⟨ codedTruth P ⟩isProp _ q) (λ p → ⟨ P ⟩isProp _ p)
    where
```

现在构造两个方向的映射。

- 对于 `to`，证明 `p : ⟨ P ⟩` 使 `⊤` 与 `P` 逻辑等价。命题外延性给出路径 `⊤ ≡ P`，再用 `cong c` 得到 `c ⊤ ≡ c P`，即 `codedTruth P` 的证明。

```agda
    to : ⟨ P ⟩ → ⟨ codedTruth P ⟩
    to p = cong c (⇔toPath (λ _ → p) (λ _ → tt*))
```

- 对于 `from`，从 `q : c ⊤ ≡ c P` 出发。类型等价 `congEquiv e` 联系命题之间的路径与编码之间的路径；其逆映射 `invEq (congEquiv e)` 还原出 `⊤ ≡ P`，再用 `subst ⟨_⟩` 沿该路径搬运 `tt*`，便得到 `P` 的证明。

```agda
    from : ⟨ codedTruth P ⟩ → ⟨ P ⟩
    from q = subst ⟨_⟩ (invEq (congEquiv e) q) tt*
```

</div>
</details>

**定理** (`ΩResizing→Resizing`) 命题宇宙换级蕴含命题换级。

**证明** 给定 `(Ω , e)`，前面的模块为每个 `P` 提供位于 `ℓ₂` 层的 `codedTruth P`。再用 `isoToEquiv` 将 `codedTruthIso P` 转成等价，所得依值对正是 `hasSize ℓ₂ P`。

```agda
ΩResizing→Resizing : ∀ {ℓ₁ ℓ₂} → ΩResizing ℓ₁ ℓ₂ → Resizing ℓ₁ ℓ₂
ΩResizing→Resizing (Ω , e) P = codedTruth P , isoToEquiv (codedTruthIso P)
  where open CodedTruth Ω e
```

## 小结

这些定义分离出了直谓式宇宙层级不会自动提供的尺寸信息。借助类型等价，高层命题获得具有相同真值内容的低层代表；命题换级逐点给出这类代表，命题宇宙换级则一次呈现整个命题宇宙。本章尚未构造这些原理的见证。「经典逻辑的边界」将从排中律导出二者。
