至此你已了解过一些在 Lean 中定义对象和函数的方法。本章我们将介绍 如何将数学命题和证明也用依值类型论的方式书写。
3.1. 命题即类型 Propositions as Types
证明依值类型论中所定义对象的断言的一种策略是 在定义语言之上再叠加一层断言语言和证明语言。 但实际上完全没必要以这种方式增加语言层次: 依值类型论本身就足够灵活且富有表达力, 完全可以在同一个大框架内同时表示断言和证明。
比如我们可以引入一种新类型 Prop 来表示命题
并引入一些构造子以利用其他命题来构造新命题。
| |
可以为每个元素 p : Prop 都引入另一个类型 Proof p
作为 p 的证明的类型。“公理”便是这个类型中的常值。
| |
然而除了公理之外,我们还需要推理规则 以便从旧证明中建立新证明。例如, 在许多命题逻辑的证明系统中, 我们都有肯定前件 Modus Ponens 推理规则:
如果有关于
Implies p q和p的证明,那么便可获得q的证明。
我们可用如下方式表示它:
| |
如果我们在
p作为假设时有q的证明, 那么我们便有Implies p q的证明。
我们可用如下方式表示它:
| |
这种尝试允许我们合理地构建断言和证明。
要确定表达式 t 是否为 p 的证明,
只需检查 t 的类型是否为 Proof p 即可。
不过还可以再进一步简化。首先
我们可以通过将 Proof p 和 p 本身合并
以避免重复书写 Proof 这个词。换句话说,
只要有了 p : Prop 我们就可以
把 p 解释为所有关于其的证明所构成的类型。
然后我们就可以把 t : p 解释为“ t 是 p 的证明”。
一旦我们实现了这种合并,
那么与蕴含相关的两条推理规则就意味着
我们可以在 Implies p q 和 p → q 之间来回切换,换句话说:
命题 p 蕴含 q 意味着存在一个函数,其
接收任何 p 的元素作为参数
并将其映射至 q 的一个元素。
如此引入连结词 Implies 是完全多余的:
我们可以直接使用依值类型论中常见的
函数空间构造子 p → q 来充当蕴含连结词。
这正是构造演算所遵循的方法,因此对于 Lean 来说也是如此。
自然演绎证明系统中和蕴含相关的两条规则能对应上
控制函数抽象和应用的两条规则,
这个现象其实是 Curry-Howard 同构 Curry-Howard Isomorphism 的一个实例,有时也称作“命题即类型 Propositions-as-Types”。事实上,
类型 Prop 是 Sort 0 的语法糖:后者即上一章提到的类型层次结构的最底层;
另外 Type u 也不过是 Sort (u+1) 的语法糖罢了。
尽管 Prop 有一些特殊的性质,但与其他类型宇宙一样,它在箭头构造子始终下是封闭的:
只要我们有 p q : Prop,那么就会有 p → q : Prop。
至少存在两种理解“命题即类型”的方式:
①对于那些对逻辑和数学持有构造主义观点的人来说
这就是对命题含义的忠实诠释,
命题 p 代表了某种数据类型,
也就是对 p 的证明所构成的类型的描述。
一个 p 的证明就是一个拥有正确类型的对象 t : p。
②而对那些不倾向于此观点的人而言,
这可被视作是一种简单的编码技巧。
对每个命题 p 我们都关联一个类型:
如果 p 为假,那么该类型为空;
如果 p 为真,那么该类型仅含单个元素——如 *。
对于后者我们可以称(与)p(相关的类型)被占据 Inhabited,
而函数的抽象和应用的规则正好可以方便我们跟踪
Prop 里面哪些元素是被占据的,
因此构造出一个元素 t : p 便意味着 p 确实是正确的,
你可以把 p 的占据者当作是“p 为真”的证据;
而一个关于 p → q 的证明则通过“p 为真”这个证据来得到“q 为真”这个证据。
确实,如果 p : Prop 是任一命题,
那么 Lean 的内核会将任意两个元素 t1 t2 : p 视作是定义等价的,
正如它会把 (fun x ↦ t) s 和 t[s/x] 视作是定义等价的一样。
这就是所谓的“证明无关性 Proof Irrelevance”,并且
这与上一段所描述的诠释方式是自洽的。这意味着
尽管我们可以把证明 t : p 当作依值类型论语言中的普通对象,
但它们不携带其他任何信息——除了“ p 为真”这一证据之外。
我们所建议的两种看待“命题即类型”的方式在本质上是有差异的。 ①从构造的角度看, 证明就是抽象的数学对象, 它由依值类型论中合适的表达式所表示;相反, ②如果我们以刚才提到的编码技巧的角度来考虑, 表达式本身其实并不携带任何有趣的东西;相反,是“ 我们可以写下它们并 检查它们是否有良好的类型” 这一事实确保了有关命题为真。也就是说, 表达式本身就是证明。
在下面的论述中,我们将在这两种说话方式之间来回切换, 有时会称一个表达式“构造”/“产生”/“返回”一个命题的证明, 有时则简单地说它“是”这样的一个证明。 这类似于计算机科学家偶尔会模糊语法和语义之间的区别: 有时称一个程序“计算”某个函数, 有时又说该程序“是”该函数。
无论如何,真正重要的只有结论。
为了用依值类型论的语言正式地描述一个数学命题,
我们需要提供一个项 p : Prop。
为了证明该断言,
我们需要展示一个项 t : p。
作为一个证明助手,Lean 的任务是
帮助我们构造这样的一个项 t 并
验证它的
格式是否良好以及
类型是否正确。
3.2. 以“命题即类型”的方式工作
在“命题即类型”范式中,任何仅涉及 → 的定理
都可以用 lambda 表达式的抽象和应用规则来证明。
Lean 里面 theorem 命令用于引入新的定理:
| |
比较一下此证明与表达式 fun x : α ↦ fun y : β ↦ x
(类型为 α → β → α,其中 α 和 β 为类型);
后者描述了一个函数,其
接收类型为 α 的参数 x
以及类型为 β 的参数 y并
返回 x。
t1 的证明也具有类似的形式,唯一的区别是
p 和 q 是 Prop 的元素而非 Type 的元素。直观地说,
在关于 p → q → p 的证明中,我们
假设 p 和 q 为真并
使用第一个假设(平凡地)
建立结论,即 p 为真。
注意到 theorem 命令其实是 def 命令的一个变体:
在“命题即类型”的对应关系下,证明定理 p → q → p
实际上和定义类型 p → q → p 下的元素是一样的,
对内核类型检查器而言两者没有任何区别。
然而定义和定理之间在实用性上还是有一些区别。 一般情况下我们完全没有必要去展开一个定理的“定义”: 由证明无关性可知一个定理的任何两个证明都是定义等价的, 一旦定理的证明被完成,我们通常只需要知道证明存在即可,至于证明具体是什么并不重要。 鉴于这一事实,Lean 会将证明标记为不可还原的 Irreducible, 以此来提示解析器 Parser,更确切地说是繁饰器 Elaborator 在处理文件时通常不需要将其展开。 事实上 Lean 通常可以并行地处理和检查证明, 因为在评估一个证明的正确性时并不需要知道另一个证明的细节。另外 定义中被引用的 section 变量会自动作为参数被添加进来,但 定理中只有那些在定理类型中被引用的变量才会被添加。 这是因为证明一个命题的方式不应影响该命题本身的陈述形式。
| |
lambda 抽象里的 hp : p 和 hq : q
可以被视作是 t1 的证明中的临时假设。
此外 Lean 还允许我们通过 show 语句
明确指定最后一个项 hp 的类型:
| |
添加这些额外信息可以
提高证明的清晰度并
帮助我们在书写证明时找出错误。
show 命令不过是个类型注解,并且
我们看到的所有版本的 t1
在 Lean 内部最终都会产生相同的项。
与普通定义一样,我们也可以将 lambda 抽象的变量移到冒号的左边:
| |
现在我们可以把定理 t1
作为一个函数来应用。
| |
axiom 会假定给定的类型下存在元素,
如此可能会破坏逻辑一致性;例如
我们可以用它来假设空类型 False 下存在一个元素:
| |
将 hp : p 声明为“公理”等同于声明 p 为真,正如 hp 所证明的那样。
把定理 t1 : p → q → p 应用到事实 hp : p(即 p 为真)
将会得到定理 t1 hp : q → p。
回想一下上一章的内容,我们也可以如下书写定理 t1:
| |
现在 t1 的类型就变成了 ∀ {p q : Prop}, p → q → p。
我们可以把它理解为“对于每一对命题 p q 我们都有 p → q → p”。
例如我们可以将所有参数移到冒号的右边:
| |
如果 p 和 q 被声明为变量,
那么 Lean 会自动为我们推广它们:
| |
在以这种方式推广 t1 之后,
我们就可以将其应用到任何一对命题上,
从而得到该一般性定理的不同实例。
| |
同样,根据“命题即类型”范式,
类型为 r → s 的变量 h 可
视作是 r → s 成立的假设或前提。
作为另一个例子,让我们来考虑上一章提到的函数复合运算—— 不过这里用的是命题而非类型。
| |
作为一个命题逻辑定理,
t2 表示的意思是什么呢?
注意:像本例中那样为假设使用 unicode 数字下标往往会很有用,
这些数字下标可通过输入 \0、\1、\2 等打出。
3.3. 命题逻辑 Propositional Logic
Lean 已经定义了所有标准的逻辑连接词和对应的记号。 命题连接词的记法如下:
| ASCII | Unicode | 编辑器快捷键 | 定义 |
|---|---|---|---|
True | True | ||
False | False | ||
Not | ¬ | \not,\neg | Not |
/\ | ∧ | \and | And |
\/ | ∨ | \or | Or |
-> | → | \to,\r,\imp | |
<-> | ↔ | \iff,\lr | Iff |
它们都接收类型 Prop 下的值作为参数。
| |
操作符的优先级如下:一元连结词 ¬ 的结合力最强,
其次是 ∧,然后是 ∨,接着是 →,最后是 ↔。举例:
a ∧ b → c ∨ d ∧ e 意为 (a ∧ b) → (c ∨ (d ∧ e))。
请记住 → 等二元关系是右结合的,因此如果我们有 p q r : Prop,
表达式 p → q → r 就应读作“如果有 p,那么如果有 q ,那么 r”。
此即为 p ∧ q → r 的柯里化形式。
在上一章中,我们发现:
lambda 抽象可被视为 → 的“引入规则”,其展示了如何“引入”或构建一个蕴含;而
lambda 应用则可被视为一个 → 的“消去规则”,其展示了如何在证明中“消去”或使用一个蕴含。
其他命题连结词在 Lean 的库(见 Prelude.core)中皆有定义且会被自动导入。
每个连结词都有规范的引入和消去规则。
3.3.1. 合取 Conjunction
表达式 And.intro h1 h2 是 p ∧ q 的证明,
它用到了 h1 : p 和 h2 : q 两个证明。
通常我们把 And.intro 称为合取引入 And-Introduction 规则。下面的例子中
我们将用 And.intro 来构建 p → q → p ∧ q 的证明。
| |
example 命令会声明一个定理,但
并不为其命名,且不将其保存在持久的语境中。
它只负责检查给定的项是否具有指定的类型。
这在解释说明时非常方便,我们会经常用到它。
表达式 And.left h 基于证明 h : p ∧ q 构建了一个 p 的证明。
类似地 And.right h 是对 q 的证明。And.left/And.right
通常被分别称为左/右合取消去 And-Elimination 规则。
| |
现在我们可以用下方的代码
来证明 p ∧ q → q ∧ p:
| |
会发现合取引入和消去规则与
笛卡尔积的配对和投影操作非常相似。区别在于:
给定 hp : p 和 hq : q,And.intro hp hq 的类型是 p ∧ q : Prop;而
给定 a : α 和 b : β,Prod.mk a b 的类型是 α × β : Type。
Prod 不能用于 Prop,而
And 不能用于 Type。
∧ 和 × 之间的相似性是 Curry-Howard 同构的另一个体现。
但与蕴涵和函数空间构造子有所不同的是,
∧ 和 × 在 Lean 中会被以不同的方式处理。
尽管如此,通过这个类比,我们刚刚构造的证明
就像是一个可以交换有序对中的元素的函数。
在“结构体和记录”一章中我们将看到
某些 Lean 类型是结构体 Structures,也就是说,
该类型是通过单个规范的构造子定义的,此构造子
利用一系列合适的参数构建该类型的下一个元素。
对于每一组 p q : Prop, p ∧ q 就是一个例子:
构造一个元素的规范方法是将 And.intro
应用于合适的参数 hp : p 和 hq : q。
Lean 允许我们使用匿名构造子表示法 Anonymous Constructor ⟨arg1, arg2, ...⟩,
只要情况如刚才一样——当相关类型是归纳类型且可通过语境推断得出时。
比如我们通常可以用 ⟨hp, hq⟩ 来代替 And.intro hp hq:
| |
这些尖括号可以通过输入
\< 和 \> 打出来。
Lean 提供了另一个有用的语法小工具:
对于一个归纳类型 Foo 下的表达式 e(可能会被应用到一些参数),
记号 e.bar 即为 Foo.bar e 的缩写。
这便于我们访问函数,我们无需打开命名空间。
比如下面两个表达式就具有相同的效果:
| |
如此一来对于 h : p ∧ q 我们就可以用
h.left 来表示 And.left h ,并用
h.right 来表示 And.right h。
我们便可将上述证明简写为如下形式:
| |
简洁与晦涩之间有一条微妙的界限,
以刚才这样的方式省略信息可能会使证明更难阅读;
但对于像上面这样简单的结构——
当 h 的类型和证明目标都非常明显时,
这种记法既简洁又有效。
我们经常会需要迭代类似 And. 这样的结构。
Lean 也允许我们将右结合的嵌套构造子压扁,
因此下述两个证明是等价的:
| |
这同样也很有用。
3.3.2. 析取 Disjunction
表达式 Or.intro_left q hp 使用证明 hp : p 构建了 p ∨ q 的证明。类似地,
表达式 Or.intro_right p hq 使用证明 hq : q 构建了 p ∨ q 的证明。
这便是左/右析取引入 Or-Introduction 规则。
| |
析取消去 Or-Elimination 规则会稍微复杂一点,思路是:
要实现通过 p ∨ q 证明 r,可以先
展示 p 能证明 r ,再
展示 q 能证明 r 。
换句话说就是分类讨论证明。
在表达式 Or.elim hpq hpr hqr 中,Or.elim
接受三个参数
hpq : p ∨ q,
hpr : p → r 和
hqr : q → r并
生成 r 的证明。
我们在下面的例子中将用 Or.elim
来证明 p ∨ q → q ∨ p。
| |
大多数情况下 Or.intro_right 和 Or.intro_left 的第一个参数
都可以被 Lean 自动推断出来,因此 Lean 提供了 Or.inr 和 Or.inl
分别作为 Or.intro_right _ 和 Or.intro_left _ 的缩写。因此
上面的证明可以变得更简洁:
| |
尽管完整表达式中包含的信息足以让 Lean 推断出 hp 和 hq 的类型。
但使用类型注解往往会使证明
变得更具易读且
有助于发现和调试错误。
由于 Or 有两个构造子,因此我们无法使用匿名构造子表示法;
尽管如此我们依然可以用 h.elim 代替 Or.elim h,
| |
同样你需要自己判断 这些缩写是否会提升或降低可读性。
3.3.3. 否定和谬误 Negation and Falsity
否定 ¬p 的定义其实为 p → False,
因此要获得 ¬p 我们就需要从 p 导出一个矛盾;类似地,
表达式 hnq hq 要产生一个 False 的证明
可以通过 hq : q 和 hnq : ¬q 来实现。
下面的例子将用上述两条规则来证明 (p → q) → ¬q → ¬p
(符号 ¬ 可以由 \not 或 \neg 打出)。
| |
连接词 False 只有一个消去规则 False.elim,
这描述了一个事实:矛盾能导出一切。这个规则
有时被称作是 无稽之谈 Ex Falso Sequitur Quodlibet,Ex Falso,或爆炸原理 Principle of Explosion。
| |
假命题所导出的任意事实 q 是 False.elim 的一个隐式参数,
而且是被自动推断出来的。这种从相互矛盾的假设中
推导出任意事实的模式很常见,可以用 absurd 来表示。
| |
再比如下面关于 ¬p → q → (q → p) → r 的证明:
| |
顺便说一句,正如 False 只有一个消去规则,
True 也只有一个引入规则 True.intro : true。
换句话说:True 就是真,并且有一个标准证明,即 True.intro。
3.3.4. 逻辑等价 Logical Equivalence
表达式 Iff.intro h1 h2 依据 h1 : p → q 和 h2 : q → p 生成了 p ↔ q 的证明。
表达式 Iff.mp h 依据 h : p ↔ q 生成了 p → q 的证明。类似地,
表达式 Iff.mpr h 依据 h : p ↔ q 生成了 q → p 的证明。
下面是 p ∧ q ↔ q ∧ p 的证明:
| |
我们可以用匿名构造子表示法,基于正反两个方向的证明来构建 p ↔ q 的证明;
我们也可以使用 .mp 和 .mpr 来代替 Iff.mp 和 Iff.mpr。
因此刚才的例子可简写为如下形式:
| |
3.4. 引入辅助子目标 Introducing Auxiliary Subgoals
正好可以在这里介绍一下 Lean 提供的另一种
构造长证明的方法——即 have 结构:
它会在证明中引入一个辅助子目标。
下面是一个小例子,改编自 3.3.1 节:
| |
表达式 have h : p := s; t 在内部会
产生项 (fun (h : p) ↦ t) s,也就是说:
s 是 p 的证明,
t 是基于假设 h : p 所期望的结论的证明,
它们俩通过 lambda 抽象和应用被组合在一起。
这个简单的语法在构建长证明时非常有用,
我们可以用多个 have 作为通向最终的证明目标的垫脚石。
Lean 还提供了一种从证明目标反向推理的结构化方法,模拟了 普通数学文献中“足以说明······ suffices to show …”的构造。 下面的例子不过是对调了上方证明的最后两行罢了。
| |
写下 suffices hq : q 会留下两条目标:
首先需要解释证明 q 足以完成对原目标 q ∧ p 的证明,
然后我们再去证明 q。
3.5. 经典逻辑 Classical Logic
目前为止我们看到的引入和消去规则都是构造主义的,也就是说, 它们是以“命题即类型”基础对逻辑连结词的一种计算性理解。 普通经典逻辑在此基础上增加了排中律 Excluded Middle, EM。 要使用这个规则就必须打开经典逻辑命名空间。
| |
从直觉上看,构造主义的“或”非常强:
承认 p ∨ q 意味着知道具体哪一个命题成立。
如果 RH 代表黎曼猜想,
那么经典数学家宁愿宣称 RH ∨ ¬RH——
尽管我们还无法断言析取式的任何一端。
排中律的一个推论是双重否定消去规则 Double-Negation Elimination, DNE:
| |
双重否定消去规则允许我们证明任何命题 p ——即
依据 ¬p 推出 False。这相当于是证明 ¬¬p。
换句话说,双重否定消去允许我们使用反证法,
这在构造主义逻辑中通常是不可能的。作为练习,
你可以试着证明相反的情况,
即 em 可以由 dne 证明。
简单版:
| |
复杂版:
| |
经典逻辑公理还允许你使用额外的证明模式,
它们在 em 的支持下是合理的。比如
我们可以以分类讨论的方式完成证明:
| |
或者你也可以用反证法来证明:
| |
如果你不习惯以构造主义的方式思考,
那么你可能需要花点时间来消化
经典逻辑推理的使用场景。
在下面的例子中它是必须的,
因为从构造主义的观点来看
知道 p 和 q 不同时为真
并不意味着知道哪一个是假的:
| |
稍后我们将看到,构造逻辑中某些情形下 “排中律”和“双重否定消去律”等是被允许的, 在这种情况下,Lean 允许在不依赖排中律的前提下 使用经典逻辑进行推理。
Lean 中用到的完整公理列表请参考公理与计算。
3.6. 逻辑命题的例子 Examples of Propositional Validities
Lean 的标准库证明了不少命题逻辑相关的正确结论, 供你在自己的证明中随便使用。 下面的列表包括一些常见的逻辑恒等式。
交换律 Commutativity:
- 答:
简单版:
1 2 3 4 5 6 7variable {p q : Prop} example : p ∧ q ↔ q ∧ p :=let cache {p q : Prop} :=λ (hpq : p ∧ q) ↦ And.intro hpq.right hpq.left ⟨cache, cache⟩复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18variable {p q : Prop} example : p ∧ q ↔ q ∧ p :=Iff.intro -- ↔ 引入 (show p ∧ q → q ∧ p from fun -- → 引入 (hpq : p ∧ q) => -- show q ∧ p from And.intro -- ∧ 引入 (show q from And.right -- ∧ 消去 (show p ∧ q from hpq)) -- (show p from And.left -- ∧ 消去 (show p ∧ q from hpq))) -- (show q ∧ p → p ∧ q from fun -- → 引入 (hqp : q ∧ p) => -- show p ∧ q from And.intro -- ∧ 引入 (show p from And.right -- ∧ 消去 (show q ∧ p from hqp)) -- (show q from And.left -- ∧ 消去 (show q ∧ p from hqp))) -- - 答:
简单版:
1 2 3 4 5 6 7 8variable {p q : Prop} example : p ∨ q ↔ q ∨ p :=let cache {p q : Prop} :=λ (hpq : p ∨ q) ↦ Or.elim hpq (λ (hp : p) ↦ Or.inr hp) (λ (hq : q) ↦ Or.inl hq) ⟨cache, cache⟩复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28variable {p q : Prop} example : p ∨ q ↔ q ∨ p :=Iff.intro -- ↔ 引入 (show p ∨ q → q ∨ p from fun -- → 引入 (hpq : p ∨ q) => -- (show q ∨ p from Or.elim -- ∨ 消去 (show p ∨ q from hpq) -- (show p → q ∨ p from fun -- → 引入 (hp : p) => -- show q ∨ p from Or.inr -- ∨ 引入 (show p from hp)) -- (show q → q ∨ p from fun -- → 引入 (hq : q) => -- show q ∨ p from Or.inl -- ∨ 引入 (show q from hq)))) -- (show q ∨ p → p ∨ q from fun -- → 引入 (hqp : q ∨ p) => -- show p ∨ q from Or.elim -- ∨ 消去 (show q ∨ p from hqp) -- (show q → p ∨ q from fun -- → 引入 (hq : q) => -- (show p ∨ q from Or.inr -- ∨ 引入 (show q from hq))) -- (show p → p ∨ q from fun -- → 引入 (hp : p) => -- (show p ∨ q from Or.inl -- ∨ 引入 (show p from hp)))) --
结合律 Associativity:
- 答:
简单版:
1 2 3 4 5 6variable {p q r : Prop} example : (p ∧ q) ∧ r ↔ p ∧ (q ∧ r) :=Iff.intro (λ ⟨⟨hp, hq⟩, hr⟩ ↦ ⟨hp, ⟨hq, hr⟩⟩) (λ ⟨hp, ⟨hq, hr⟩⟩ ↦ ⟨⟨hp, hq⟩, hr⟩)复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28variable {p q r : Prop} example : (p ∧ q) ∧ r ↔ p ∧ (q ∧ r) :=Iff.intro -- ↔ 引入 (show (p ∧ q) ∧ r → p ∧ (q ∧ r) from fun -- → 引入 (hpqr : (p ∧ q) ∧ r) => -- show p ∧ (q ∧ r) from And.intro -- ∧ 引入 (show p from And.left -- ∧ 消去 (show p ∧ q from And.left -- ∧ 消去 (show (p ∧ q) ∧ r from hpqr))) -- (show q ∧ r from And.intro -- ∧ 引入 (show q from And.right -- ∧ 消去 (show p ∧ q from And.left -- ∧ 消去 (show (p ∧ q) ∧ r from hpqr))) -- (show r from And.right -- ∧ 消去 (show (p ∧ q) ∧ r from hpqr)))) -- (show p ∧ (q ∧ r) → (p ∧ q) ∧ r from fun -- → 引入 (hpqr : p ∧ (q ∧ r)) => -- show (p ∧ q) ∧ r from And.intro -- ∧ 引入 (show p ∧ q from And.intro -- ∧ 引入 (show p from And.left -- ∧ 消去 (show p ∧ (q ∧ r) from hpqr)) -- (show q from And.left -- ∧ 消去 (show q ∧ r from And.right -- ∧ 消去 (show p ∧ (q ∧ r) from hpqr)))) -- (show r from And.right -- ∧ 消去 (show q ∧ r from And.right -- ∧ 消去 (show p ∧ (q ∧ r) from hpqr)))) -- - 答:
简单版:
1 2 3 4 5 6 7 8 9 10 11variable {p q r : Prop} example : p ∨ (q ∧ r) ↔ (p ∨ q) ∧ (p ∨ r) :=Iff.intro (λ | Or.inl hp => ⟨Or.inl hp, Or.inl hp⟩ | Or.inr ⟨hq, hr⟩ => ⟨Or.inr hq, Or.inr hr⟩) (λ | ⟨Or.inl hp, _⟩ => Or.inl hp | ⟨_, Or.inl hp⟩ => Or.inl hp | ⟨Or.inr hq, Or.inr hr⟩ => Or.inr ⟨hq, hr⟩)复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48variable {p q r : Prop} example : (p ∨ q) ∨ r ↔ p ∨ (q ∨ r) :=Iff.intro -- ↔ 引入 (show (p ∨ q) ∨ r → p ∨ (q ∨ r) from fun -- → 引入 (hpqr : (p ∨ q) ∨ r) => -- (show p ∨ (q ∨ r) from Or.elim -- ∨ 消去 (show (p ∨ q) ∨ r from hpqr) -- (show p ∨ q → p ∨ (q ∨ r) from fun -- → 引入 (hpq : p ∨ q) => -- (show p ∨ (q ∨ r) from Or.elim -- ∨ 消去 (show p ∨ q from hpq) -- (show p → p ∨ (q ∨ r) from fun -- → 引入 (hp : p) => -- (show p ∨ (q ∨ r) from Or.inl -- ∨ 引入 (show p from hp))) -- (show q → p ∨ (q ∨ r) from fun -- → 引入 (hq : q) => -- (show p ∨ (q ∨ r) from Or.inr -- ∨ 引入 (show q ∨ r from Or.inl -- ∨ 引入 (show q from hq)))))) -- (show r → p ∨ (q ∨ r) from fun -- → 引入 (hr : r) => -- (show p ∨ (q ∨ r) from Or.inr -- ∨ 引入 (show q ∨ r from Or.inr -- ∨ 引入 (show r from hr)))))) -- (show p ∨ (q ∨ r) → (p ∨ q) ∨ r from fun -- → 引入 (hpqr : p ∨ (q ∨ r)) => -- (show (p ∨ q) ∨ r from Or.elim -- ∨ 消去 (show p ∨ (q ∨ r) from hpqr) -- (show p → (p ∨ q) ∨ r from fun -- → 引入 (hp : p) => -- (show (p ∨ q) ∨ r from Or.inl -- ∨ 引入 (show p ∨ q from Or.inl -- ∨ 引入 (show p from hp)))) -- (show q ∨ r → (p ∨ q) ∨ r from fun -- → 引入 (hqr : q ∨ r) => -- (show (p ∨ q) ∨ r from Or.elim -- ∨ 消去 (show q ∨ r from hqr) -- (show q → (p ∨ q) ∨ r from fun -- → 引入 (hq : q) => -- (show (p ∨ q) ∨ r from Or.inl -- ∨ 引入 (show p ∨ q from Or.inr -- ∨ 引入 (show q from hq)))) -- (show r → (p ∨ q) ∨ r from fun -- → 引入 (hr : r) => -- (show (p ∨ q) ∨ r from Or.inr -- ∨ 引入 (show r from hr))))))) --
分配律 Distributivity:
p ∧ (q ∨ r) ↔ (p ∧ q) ∨ (p ∧ r)答:简单版:
1 2 3 4 5 6 7 8 9 10variable {p q r : Prop} example : p ∧ (q ∨ r) ↔ (p ∧ q) ∨ (p ∧ r) :=Iff.intro (λ | ⟨hp, Or.inl hq⟩ => Or.inl ⟨hp, hq⟩ | ⟨hp, Or.inr hr⟩ => Or.inr ⟨hp, hr⟩) (λ | Or.inl ⟨hp, hq⟩ => ⟨hp, Or.inl hq⟩ | Or.inr ⟨hp, hr⟩ => ⟨hp, Or.inr hr⟩)复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43variable {p q r : Prop} example : p ∧ (q ∨ r) ↔ (p ∧ q) ∨ (p ∧ r) :=Iff.intro -- ↔ 引入 (show p ∧ (q ∨ r) → (p ∧ q) ∨ (p ∧ r) from fun -- → 引入 (hpqr : p ∧ (q ∨ r)) => -- show (p ∧ q) ∨ (p ∧ r) from Or.elim -- ∨ 消去 (show q ∨ r from And.right -- ∧ 消去 (show p ∧ (q ∨ r) from hpqr)) -- (show q → (p ∧ q) ∨ (p ∧ r) from fun -- → 引入 (hq : q) => -- show (p ∧ q) ∨ (p ∧ r) from Or.inl -- ∨ 引入 (show p ∧ q from And.intro -- ∧ 引入 (show p from And.left -- ∧ 消去 (show p ∧ (q ∨ r) from hpqr)) -- (show q from hq))) -- (show r → (p ∧ q) ∨ (p ∧ r) from fun -- → 引入 (hr : r) => -- show (p ∧ q) ∨ (p ∧ r) from Or.inr -- ∨ 引入 (show p ∧ r from And.intro -- ∧ 引入 (show p from And.left -- ∧ 消去 (show p ∧ (q ∨ r) from hpqr)) -- (show r from hr)))) -- (show (p ∧ q) ∨ (p ∧ r) → p ∧ (q ∨ r) from fun -- → 引入 (hpqpr : (p ∧ q) ∨ (p ∧ r)) => -- show p ∧ (q ∨ r) from Or.elim -- ∨ 消去 (show (p ∧ q) ∨ (p ∧ r) from hpqpr) -- (show p ∧ q → p ∧ (q ∨ r) from fun -- → 引入 (hpq : p ∧ q) => -- show p ∧ (q ∨ r) from And.intro -- ∧ 引入 (show p from And.left -- ∧ 消去 (show p ∧ q from hpq)) -- (show q ∨ r from Or.inl -- ∨ 引入 (show q from And.right -- ∧ 消去 (show p ∧ q from hpq)))) -- (show p ∧ r → p ∧ (q ∨ r) from fun -- → 引入 (hpr : p ∧ r) => -- show p ∧ (q ∨ r) from And.intro -- ∧ 引入 (show p from And.left -- ∧ 消去 (show p ∧ r from hpr)) -- (show q ∨ r from Or.inr -- ∨ 引入 (show r from And.right -- ∧ 消去 (show p ∧ r from hpr))))) --p ∨ (q ∧ r) ↔ (p ∨ q) ∧ (p ∨ r)答:简单版:
1 2 3 4 5 6 7 8 9 10 11variable {p q r : Prop} example : p ∨ (q ∧ r) ↔ (p ∨ q) ∧ (p ∨ r) :=Iff.intro (λ | Or.inl hp => ⟨Or.inl hp, Or.inl hp⟩ | Or.inr ⟨hq, hr⟩ => ⟨Or.inr hq, Or.inr hr⟩) (λ | ⟨Or.inl hp, _⟩ => Or.inl hp | ⟨_, Or.inl hp⟩ => Or.inl hp | ⟨Or.inr hq, Or.inr hr⟩ => Or.inr ⟨hq, hr⟩)复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52variable {p q r : Prop} example : p ∨ (q ∧ r) ↔ (p ∨ q) ∧ (p ∨ r) :=Iff.intro -- ↔ 引入 (show p ∨ (q ∧ r) → (p ∨ q) ∧ (p ∨ r) from fun -- → 引入 (hpqr : p ∨ (q ∧ r)) => -- (show (p ∨ q) ∧ (p ∨ r) from And.intro -- ∧ 引入 (show p ∨ q from Or.elim -- ∨ 消去 (show p ∨ (q ∧ r) from hpqr) -- (show p → p ∨ q from fun -- → 引入 (hp : p) => -- show p ∨ q from Or.inl -- ∨ 引入 (show p from hp)) -- (show q ∧ r → p ∨ q from fun -- → 引入 (hqr : q ∧ r) => -- (show p ∨ q from Or.inr -- ∨ 引入 (show q from And.left -- ∧ 消去 (show q ∧ r from hqr))))) -- (show p ∨ r from Or.elim -- ∨ 消去 (show p ∨ (q ∧ r) from hpqr) -- (show p → p ∨ r from fun -- → 引入 (hp : p) => -- show p ∨ r from Or.inl hp) -- ∨ 引入 (show q ∧ r → p ∨ r from fun -- → 引入 (hqr : q ∧ r) => -- show p ∨ r from Or.inr -- ∨ 引入 (show r from And.right -- ∧ 消去 (show q ∧ r from hqr)))))) -- (show (p ∨ q) ∧ (p ∨ r) → p ∨ (q ∧ r) from fun -- → 引入 (hpqpr : (p ∨ q) ∧ (p ∨ r)) => -- (show p ∨ (q ∧ r) from Or.elim -- ∨ 消去 (show p ∨ q from And.left -- ∧ 消去 (show (p ∨ q) ∧ (p ∨ r) from hpqpr)) -- (show p → p ∨ (q ∧ r) from fun -- → 引入 (hp : p) => -- (show p ∨ (q ∧ r) from Or.inl -- ∨ 引入 (show p from hp))) -- (show q → p ∨ (q ∧ r) from fun -- → 引入 (hq : q) => -- (show p ∨ (q ∧ r) from Or.elim -- ∨ 消去 (show p ∨ r from And.right -- ∧ 消去 (show (p ∨ q) ∧ (p ∨ r) from hpqpr)) -- (show p → p ∨ (q ∧ r) from fun -- → 引入 (hp' : p) => -- (show p ∨ (q ∧ r) from Or.inl -- ∨ 引入 (show p from hp'))) -- (show r → p ∨ (q ∧ r) from fun -- → 引入 (hr : r) => -- (show p ∨ (q ∧ r) from Or.inr -- ∨ 引入 (show q ∧ r from And.intro -- ∧ 引入 (show q from hq) -- (show r from hr)))))))) --
其他性质:
- 答:
简单版:
1 2 3 4 5 6 7 8 9 10 11variable {p q r : Prop} example : (p → q → r) ↔ (p ∧ q → r) :=Iff.intro (λ (hpqr : p → q → r) ↦ λ ⟨hp, hq⟩ => hpqr hp hq) (λ (hpqr : p ∧ q → r) ↦ λ (hp : p) ↦ λ (hq : q) ↦ hpqr ⟨hp, hq⟩)复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29variable {p q r : Prop} def To.elim {p q : Prop} : (p → q) → p → q :=λ (hpq : p → q) (hp : p) ↦ hpq hp example : (p → (q → r)) ↔ (p ∧ q → r) :=Iff.intro -- ↔ 引入 (show (p → (q → r)) → (p ∧ q → r) from fun -- → 引入 (hpqr : p → (q → r)) => -- (show (p ∧ q) → r from fun -- → 引入 (hpq : p ∧ q) => -- (show r from To.elim -- → 消去 (show q → r from To.elim -- → 消去 (show p → (q → r) from hpqr) -- (show p from And.left -- ∧ 消去 (show p ∧ q from hpq))) -- (show q from And.right -- ∧ 消去 (show p ∧ q from hpq))))) -- (show (p ∧ q → r) → p → (q → r) from fun -- → 引入 (hpqr : p ∧ q → r) => -- (show p → q → r from fun -- → 引入 (hp : p) => -- (show q → r from fun -- → 引入 (hq : q) => -- (show r from To.elim -- → 消去 (show p ∧ q → r from hpqr) -- (show p ∧ q from And.intro -- ∧ 引入 (show p from hp) -- (show q from hq)))))) -- ((p ∨ q) → r) ↔ (p → r) ∧ (q → r)答:简单版:
1 2 3 4 5 6 7 8 9 10 11variable {p q r : Prop} example : ((p ∨ q) → r) ↔ (p → r) ∧ (q → r) :=Iff.intro (λ (hpqr : (p ∨ q) → r) ↦ And.intro (λ (hp : p) ↦ hpqr (Or.inl hp)) (λ (hq : q) ↦ hpqr (Or.inr hq))) (λ ⟨hpr, hqr⟩ ↦ (λ | Or.inl hp => hpr hp | Or.inr hq => hqr hq))复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40variable {p q r : Prop} def To.elim {p q : Prop} : (p → q) → p → q :=λ (hpq : p → q) (hp : p) ↦ hpq hp example : ((p ∨ q) → r) ↔ (p → r) ∧ (q → r) :=Iff.intro -- ↔ 引入 (show ((p ∨ q) → r) → (p → r) ∧ (q → r) from fun -- → 引入 (hpqr : (p ∨ q) → r) => -- (show (p → r) ∧ (q → r) from And.intro -- ∧ 引入 (show p → r from fun -- → 引入 (hp : p) => -- show r from To.elim -- → 消去 (show (p ∨ q) → r from hpqr) -- (show p ∨ q from Or.inl -- ∨ 引入 (show p from hp))) -- (show q → r from fun -- → 引入 (hq : q) => -- show r from To.elim -- → 消去 (show (p ∨ q) → r from hpqr) -- (show p ∨ q from Or.inr -- ∨ 引入 (show q from hq))))) -- (show (p → r) ∧ (q → r) → ((p ∨ q) → r) from fun -- → 引入 (hpqr : (p → r) ∧ (q → r)) => -- (show (p ∨ q) → r from fun -- → 引入 (hpq : p ∨ q) => -- (show r from Or.elim -- ∨ 消去 (show p ∨ q from hpq) -- (show p → r from fun -- → 引入 (hp : p) => -- (show r from To.elim -- → 消去 (show p → r from And.left -- ∧ 消去 (show (p → r) ∧ (q → r) from hpqr)) -- (show p from hp))) -- (show q → r from fun -- → 引入 (hq : q) => -- (show r from To.elim -- → 消去 (show q → r from And.right -- ∧ 消去 (show (p → r) ∧ (q → r) from hpqr)) -- (show q from hq)))))) --- 答:这其实就是 8 的特例。
简单版:
1 2 3 4 5 6 7 8 9 10 11variable {p q : Prop} example : ¬(p ∨ q) ↔ ¬p ∧ ¬q :=Iff.intro (λ (hnpq : ¬(p ∨ q)) ↦ ⟨(λ (hp : p) ↦ hnpq (Or.inl hp)), (λ (hq : q) ↦ hnpq (Or.inr hq))⟩) (λ ⟨hnp, hnq⟩ ↦ λ | Or.inl hp => hnp hp | Or.inr hq => hnq hq)复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40variable {p q : Prop} def To.elim {p q : Prop} : (p → q) → p → q :=λ (hpq : p → q) (hp : p) ↦ hpq hp example : ¬(p ∨ q) ↔ ¬p ∧ ¬q :=Iff.intro -- ↔ 引入 (show ¬(p ∨ q) → ¬p ∧ ¬q from fun -- → 引入 (hnpq : ¬(p ∨ q)) => -- (show ¬p ∧ ¬q from And.intro -- ∧ 引入 (show p → False from fun -- ¬ 引入 (hp : p) => -- (show False from To.elim -- ¬ 消去 (show p ∨ q → False from hnpq) -- (show p ∨ q from Or.inl -- ∨ 引入 (show p from hp)))) -- (show q → False from fun -- ¬ 引入 (hq : q) => -- show False from To.elim -- ¬ 消去 (show p ∨ q → False from hnpq) -- (show p ∨ q from Or.inr -- ∨ 引入 (show q from hq))))) -- (show ¬p ∧ ¬q → ¬(p ∨ q) from fun -- → 引入 (hnpnq : ¬p ∧ ¬q) => -- (show ¬(p ∨ q) from fun -- ¬ 引入 (hpq : p ∨ q) => -- (show False from Or.elim -- ∨ 消去 (show p ∨ q from hpq) -- (show p → False from fun -- ¬ 引入 (hp : p) => -- (show False from To.elim -- (show ¬p from And.left -- ∧ 消去 (show ¬p ∧ ¬q from hnpnq)) -- (show p from hp))) -- (show q → False from fun -- ¬ 引入 (hq : q) => -- (show False from To.elim -- ¬ 消去 (show ¬q from And.right -- ∧ 消去 (show ¬p ∧ ¬q from hnpnq)) -- (show q from hq)))))) -- - 答:
简单版:
1 2 3 4 5 6variable {p q : Prop} example : ¬p ∨ ¬q → ¬(p ∧ q) :=(λ | Or.inl hnp => λ ⟨hp, _⟩ => hnp hp | Or.inr hnq => λ ⟨_, hq⟩ => hnq hq)复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24variable {p q : Prop} def To.elim {p q : Prop} : (p → q) → p → q :=λ (hpq : p → q) (hp : p) ↦ hpq hp example : ¬p ∨ ¬q → ¬(p ∧ q) :=show ¬p ∨ ¬q → ¬(p ∧ q) from fun -- → 引入 (hnpnq : ¬p ∨ ¬q) => -- (show ¬(p ∧ q) from fun -- ¬ 引入 (hpq : p ∧ q) => -- (show False from Or.elim -- ∨ 消去 (show ¬p ∨ ¬q from hnpnq) -- (show ¬p → False from fun -- ¬ 引入 (hnp : ¬p) => -- (show False from To.elim -- → 消去 (show ¬p from hnp) -- (show p from And.left -- ∧ 消去 (show p ∧ q from hpq)))) -- (show ¬q → False from fun -- ¬ 引入 (hnq : ¬q) => -- (show False from To.elim -- → 消去 (show ¬q from hnq) -- (show q from And.right -- ∧ 消去 (show p ∧ q from hpq)))))) -- - 答:
简单版:
1 2 3 4variable {p : Prop} example : ¬(p ∧ ¬p) :=(λ ⟨hp, hnp⟩ ↦ hnp hp)复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13variable {p : Prop} def To.elim {p q : Prop} : (p → q) → p → q :=λ (hpq : p → q) (hp : p) ↦ hpq hp example : ¬(p ∧ ¬p) :=show (p ∧ ¬p) → False from fun -- ¬ 引入 (hpnp : p ∧ ¬p) => -- show False from To.elim -- ¬ 消去 (show ¬p from And.right -- ∧ 消去 (show p ∧ ¬p from hpnp)) -- (show p from And.left -- ∧ 消去 (show p ∧ ¬p from hpnp)) -- - 答:
简单版:
1 2 3 4 5 6variable {p q : Prop} example : p ∧ ¬q → ¬(p → q) :=λ ⟨hp, hnq⟩ ↦ λ (hpq : p → q) ↦ hnq (hpq hp)复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17variable {p q : Prop} def To.elim {p q : Prop} : (p → q) → p → q :=λ (hpq : p → q) (hp : p) ↦ hpq hp example : p ∧ ¬q → ¬(p → q) :=show p ∧ ¬q → (p → q) → False from fun -- → 引入 (hpnq : p ∧ ¬q) => -- (show (p → q) → False from fun -- ¬ 引入 (hpq : p → q) => -- show False from To.elim -- ¬ 消去 (show ¬q from And.right -- ∧ 消去 (show p ∧ ¬q from hpnq)) -- (show q from To.elim -- → 消去 (show p → q from hpq) -- (show p from And.left -- ∧ 消去 (show p ∧ ¬q from hpnq)))) -- - 答:这其实等价于
(¬p ∧ p) → q。简单版:
1 2 3 4 5 6variable {p q : Prop} example : ¬p → (p → q) :=λ (hnp : ¬p) ↦ λ (hp : p) ↦ absurd hp hnp复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14variable {p q : Prop} def To.elim {p q : Prop} : (p → q) → p → q :=λ (hpq : p → q) (hp : p) ↦ hpq hp example : ¬p → (p → q) :=show ¬p → (p → q) from fun -- → 引入 (hnp : ¬p) => -- (show p → q from fun -- → 引入 (hp : p) => -- (show q from False.elim -- ⊥ 消去 (show False from To.elim -- ¬ 消去 (show ¬p from hnp) -- (show p from hp)))) -- - 答:
简单版:
1 2 3 4 5 6 7variable {p q : Prop} example : (¬p ∨ q) → (p → q) :=λ (hnpq : ¬p ∨ q) ↦ λ (hp : p) ↦ match hnpq with -- 对应 Or.elim | Or.inl hnp => absurd hp hnp | Or.inr hq => hq复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21variable {p q : Prop} def To.elim {p q : Prop} : (p → q) → p → q :=λ (hpq : p → q) (hp : p) ↦ hpq hp example : (¬p ∨ q) → (p → q) :=show (¬p ∨ q) → (p → q) from fun -- → 引入 (hnpq : ¬p ∨ q) => -- (show p → q from fun -- → 引入 (hp : p) => -- (show q from Or.elim -- ∨ 消去 (show ¬p ∨ q from hnpq ) -- (show ¬p → q from fun -- → 引入 (hnp : ¬p) => -- (show q from False.elim -- ⊥ 消去 (show False from To.elim -- ¬ 消去 (show ¬p from hnp) -- (show p from hp)))) -- (show q → q from fun -- → 引入 (hq : q) => -- (show q from hq)))) -- - 答:
简单版:
1 2 3 4 5 6 7 8variable {p q : Prop} example : p ∨ False ↔ p :=Iff.intro (λ (hpf : p ∨ False) ↦ match hpf with -- 对应 Or.elim | Or.inl hp => hp | Or.inr hf => False.elim hf) (λ (hp : p) ↦ Or.inl hp)复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19variable {p : Prop} example : p ∨ False ↔ p :=Iff.intro -- ↔ 引入 (show p ∨ False → p from fun -- → 引入 (hpf : p ∨ False) => -- (show p from Or.elim -- ∨ 消去 (show p ∨ False from hpf) -- (show p → p from fun -- → 引入 (hp : p) => -- (show p from hp)) -- (show False → p from fun -- → 引入 (hf : False) => -- (show p from False.elim -- ⊥ 消去 (show False from hf))))) -- (show p → p ∨ False from fun -- → 引入 (hp : p) => -- (show p ∨ False from Or.inl -- ∨ 引入 (show p from hp))) -- - 答:
简单版:
1 2 3 4 5variable {p : Prop} example : p ∧ False ↔ False :=⟨(λ (hpf : p ∧ False) ↦ hpf.right), (λ (hf : False) ↦ ⟨False.elim hf, hf⟩)⟩复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14variable {p : Prop} example : p ∧ False ↔ False :=Iff.intro -- ↔ 引入 (show p ∧ False → False from fun -- → 引入 (hpf : p ∧ False) => -- (show False from And.right -- ∧ 消去 (show p ∧ False from hpf))) -- (show False → p ∧ False from fun -- → 引入 (hf : False) => -- (show p ∧ False from And.intro -- ∧ 引入 (show p from False.elim -- ⊥ 消去 (show False from hf)) -- (show False from hf))) -- - 答:
简单版:
1 2 3 4 5 6 7variable {p : Prop} example : ¬(p ↔ ¬p) :=λ (hpnp : p ↔ ¬p) ↦ let hnp : p → False := λ (hp : p) ↦ hpnp.mp hp hp let hp : p := hpnp.mpr hnp hpnp.mp hp hp复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26variable {p : Prop} def To.elim {p q : Prop} : (p → q) → p → q :=λ (hpq : p → q) (hp : p) ↦ hpq hp example : ¬(p ↔ ¬p) :=show (p ↔ ¬p) → False from fun -- → 引入 (hpnp : p ↔ ¬p) => -- let hnp := show p → False from fun -- → 引入 (hp : p) => -- show False from To.elim -- ¬ 消去 (show p → False from To.elim -- → 消去 (show p → ¬p from Iff.mp -- ↔ 消去 (show p ↔ ¬p from hpnp)) -- (show p from hp)) -- (show p from hp) -- let hp := show p from To.elim -- → 消去 (show ¬p → p from Iff.mpr -- ↔ 消去 (show p ↔ ¬p from hpnp)) -- (show ¬p from hnp) -- (show False from To.elim -- ¬ 消去 (show ¬p from To.elim -- → 消去 (show p → ¬p from Iff.mp -- ↔ 消去 (show p ↔ ¬p from hpnp)) -- (show p from hp)) -- (show p from hp)) -- - 答:
简单版:
1 2 3 4 5 6 7 8 9 10variable {p q : Prop} example : (p ↔ q) → (¬q ↔ ¬p) :=λ (hpq : p ↔ q) ↦ let cache {p q : Prop} := λ (hpq : p → q) ↦ λ (hnq : ¬q) ↦ λ (hp : p) ↦ hnq (hpq hp) ⟨cache hpq.mp, cache hpq.mpr⟩复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29variable {p q : Prop} def To.elim {p q : Prop} : (p → q) → p → q :=λ (hpq : p → q) (hp : p) ↦ hpq hp example : (p ↔ q) → (¬q ↔ ¬p) :=let cache {p q : Prop} :=show (p → q) → (¬q → ¬p) from fun -- → 引入 (hpq : p → q) => -- (show ¬q → ¬p from fun -- → 引入 (hnq : ¬q) => -- (show p → False from fun -- ¬ 引入 (hp : p) => -- (show False from To.elim -- ¬ 消去 (show ¬q from hnq ) -- (show q from To.elim -- → 消去 (show p → q from hpq) -- (show p from hp))))) -- show (p ↔ q) → (¬q ↔ ¬p) from fun -- → 引入 (hpq : p ↔ q) => -- show ¬q ↔ ¬p from Iff.intro -- ↔ 引入 (show ¬q → ¬p from To.elim -- → 消去 (show (p → q) → (¬q → ¬p) from cache) -- (show p → q from Iff.mp -- ↔ 消去 (show p ↔ q from hpq))) -- (show ¬p → ¬q from To.elim -- → 消去 (show (q → p) → (¬p → ¬q) from cache) -- (show q → p from Iff.mpr -- ↔ 消去 (show p ↔ q from hpq))) --
依赖经典逻辑推理的例子:
(p → q ∨ r) → ((p → q) ∨ (p → r))答:简单版:
1 2 3 4 5 6 7 8 9 10variable {p q r : Prop} open Classical example : (p → (q ∨ r)) → ((p → q) ∨ (p → r)) :=λ (hpqr : p → (q ∨ r)) ↦ byCases (λ (hpq : p → q ) ↦ Or.inl hpq) (λ (hnpq : ¬(p → q)) ↦ Or.inr (λ (hp : p) ↦ match (hpqr hp) with | Or.inl hq => absurd (λ (_ : p) ↦ hq) hnpq | Or.inr hr => hr))复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36variable {p q r : Prop} def To.elim {p q : Prop} : (p → q) → p → q :=λ (hpq : p → q) (hp : p) ↦ hpq hp open Classical example : (p → (q ∨ r)) → ((p → q) ∨ (p → r)) :=show (p → (q ∨ r)) → ((p → q) ∨ (p → r)) from fun -- → 引入 (hpqr : p → q ∨ r) => -- show (p → q) ∨ (p → r) from Or.elim -- (show (p → q) ∨ ¬(p → q) from (em (p → q))) -- (p → q) ∨ (p → r) (show (p → q) → ((p → q) ∨ (p → r)) from fun -- → 引入 (hpq : p → q ) => -- (show (p → q) ∨ (p → r) from Or.inl -- ∨ 引入 (show p → q from hpq))) -- (show ¬(p → q) → ((p → q) ∨ (p → r)) from fun -- → 引入 (hnpq : ¬(p → q)) => -- (show (p → q) ∨ (p → r) from Or.inr -- ∨ 引入 (show p → r from fun -- → 引入 (hp : p) => -- (show r from Or.elim -- ∨ 消去 (show q ∨ r from To.elim -- → 消去 (show p → q ∨ r from hpqr) -- (show p from hp)) -- (show q → r from fun -- → 引入 (hq : q) => -- (show r from False.elim -- ⊥ 消去 (show False from To.elim -- ¬ 消去 (show ¬(p → q) from hnpq) -- (show p → q from fun -- → 引入 (_ : p) => -- (show q from hq))))) -- (show r → r from fun -- → 引入 (hr : r) => -- (show r from hr)))))) --- 答:
简单版:
1 2 3 4 5 6 7 8 9variable {p q : Prop} open Classical example : ¬(p ∧ q) → (¬p ∨ ¬q) :=λ (hnpq : ¬(p ∧ q)) ↦ byCases (λ (hp : p) ↦ Or.inr (λ (hq : q) ↦ hnpq ⟨hp, hq⟩)) (λ (hnp : ¬p) ↦ Or.inl hnp)复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26variable {p q : Prop} def To.elim {p q : Prop} : (p → q) → p → q :=λ (hpq : p → q) (hp : p) ↦ hpq hp open Classical example : ¬(p ∧ q) → (¬p ∨ ¬q) :=show ¬(p ∧ q) → (¬p ∨ ¬q) from fun -- → 引入 (hnpq : ¬(p ∧ q)) => -- show (¬p ∨ ¬q) from Or.elim -- ∨ 消去 (show p ∨ ¬p from (em p)) -- (show p →(¬p ∨ ¬q) from fun -- → 引入 (hp : p) => -- (show ¬p ∨ ¬q from Or.inr -- ∨ 引入 (show q → False from fun -- ¬ 引入 (hq : q) => -- show False from To.elim -- ¬ 消去 (show ¬(p ∧ q) from hnpq) -- (show p ∧ q from And.intro -- ∧ 引入 (show p from hp) -- (show q from hq))))) -- (show ¬p →(¬p ∨ ¬q) from fun -- → 引入 (hnp : ¬p) => -- (show ¬p ∨ ¬q from Or.inl -- ∨ 引入 (show ¬p from hnp))) -- - 答:
简单版:
1 2 3 4 5 6 7 8 9 10variable {p q : Prop} open Classical example : ¬(p → q) → p ∧ ¬q :=λ (hnpq : ¬(p → q)) ↦ byContradiction (λ (hnpnq : ¬(p ∧ ¬q)) ↦ hnpq (λ (hp : p) ↦ byCases (λ (hq : q) ↦ hq) (λ (hnq : ¬q) ↦ absurd ⟨hp, hnq⟩ hnpnq)))复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36variable {p q : Prop} def To.elim {p q : Prop} : (p → q) → p → q :=λ (hpq : p → q) (hp : p) ↦ hpq hp open Classical theorem dne {p : Prop} : ¬¬p → p :=λ (hnnp : ¬¬p) ↦ byCases (λ (hp : p) ↦ hp) (λ (hnp : ¬p) ↦ absurd hnp hnnp) example : ¬(p → q) → p ∧ ¬q :=show ¬(p → q) → p ∧ ¬q from fun -- → 引入 (hnpq : ¬(p → q)) => -- (show p ∧ ¬q from To.elim -- → 消去 (show ¬¬(p ∧ ¬q) → (p ∧ ¬q) from dne) -- (show ¬(p ∧ ¬q) → False from fun -- ¬ 引入 (hnpnq : ¬(p ∧ ¬q)) => -- show False from To.elim -- ¬ 消去 (show ¬(p → q) from hnpq) -- (show p → q from fun -- → 引入 (hp : p) => -- (show q from Or.elim -- ∨ 消去 (show (q ∨ ¬q) from em q) -- (show q → q from fun -- → 引入 (hq : q) => -- show q from hq) -- (show ¬q → q from fun -- → 引入 (hnq : ¬q) => -- (show q from False.elim -- ⊥ 消去 (show False from To.elim -- ¬ 消去 (show ¬(p ∧ ¬q) from hnpnq) -- (show p ∧ ¬q from And.intro -- ∧ 引入 (show p from hp) -- (show ¬q from hnq))))))))) -- - 答:
简单版:
1 2 3 4 5 6 7 8variable {p q : Prop} open Classical example : (p → q) → (¬p ∨ q) :=λ (hpq : p → q) ↦ match (em p) with | Or.inl hp => Or.inr (hpq hp) | Or.inr hnp => Or.inl hnp复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22variable {p q : Prop} def To.elim {p q : Prop} : (p → q) → p → q :=λ (hpq : p → q) (hp : p) ↦ hpq hp open Classical example : (p → q) → (¬p ∨ q) :=show (p → q) → (¬p ∨ q) from fun -- → 引入 (hpq : p → q) => -- (show ¬p ∨ q from Or.elim -- ∨ 消去 (show p ∨ ¬p from em p) -- (show p → ¬p ∨ q from fun -- → 引入 (hp : p) => -- show ¬p ∨ q from Or.inr -- ∨ 引入 (show q from To.elim -- → 消去 (show p → q from hpq) -- (show p from hp))) -- (show ¬p → ¬p ∨ q from fun -- → 引入 (hnp : ¬p) => -- (show ¬p ∨ q from Or.inl -- ∨ 引入 (show ¬p from hnp)))) -- - 答:
简单版:
1 2 3 4 5 6 7 8 9variable {p q : Prop} open Classical example : (¬q → ¬p) → (p → q) :=λ (hnqnp : ¬q → ¬p) ↦ λ (hp : p) ↦ byCases (λ (hq : q) ↦ hq) (λ (hnq : ¬q) ↦ absurd hp (hnqnp hnq))复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24variable {p q : Prop} def To.elim {p q : Prop} : (p → q) → p → q :=λ (hpq : p → q) (hp : p) ↦ hpq hp open Classical example : (¬q → ¬p) → (p → q) :=show (¬q → ¬p) → (p → q) from fun -- → 引入 (hnqnp : ¬q → ¬p) => -- (show p → q from fun -- → 引入 (hp : p) => -- (show q from Or.elim -- ∨ 消去 (show q ∨ ¬q from em q) -- (show q → q from fun -- → 引入 (hq : q) => -- (show q from hq)) -- (show ¬q → q from fun -- → 引入 (hnq : ¬q) => -- (show q from False.elim -- ⊥ 消去 (show False from To.elim -- ¬ 消去 (show ¬q → ¬p from hnqnp) -- (show ¬q from hnq) -- (show p from hp)))))) -- - 答:见前面的注
- 答:
简单版:
1 2 3 4 5 6 7 8variable {p q : Prop} open Classical example : ((p → q) → p) → p :=λ (h : (p → q) → p) ↦ byCases (λ (hp : p) ↦ hp) (λ (hnp : ¬p) ↦ h (λ (hp : p) ↦ absurd hp hnp))复杂版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25variable (p q : Prop) def To.elim {p q : Prop} : (p → q) → p → q :=λ (hpq : p → q) (hp : p) ↦ hpq hp open Classical example : ((p → q) → p) → p :=show ((p → q) → p) → p from fun -- → 引入 (hpqp : (p → q) → p) => -- (show p from Or.elim -- ∨ 消去 (show p ∨ ¬p from em p) -- (show p → p from fun -- → 引入 (hp : p) => -- show p from hp) -- (show ¬p → p from fun -- → 引入 (hnp : ¬p) => -- show p from To.elim -- → 消去 (show (p → q) → p from hpqp) -- (show p → q from fun -- → 引入 (hp : p) => -- (show q from False.elim -- ⊥ 消去 (show False from To.elim -- ¬ 消去 (show ¬p from hnp) -- (show p from hp)))))) --
sorry 标识符可以神奇地
生成任何东西的证明或者是
提供任何类型的对象。当然
作为一种证明方法它是不可靠的,
比如你可以使用它来证明 False;并且
在文件中使用或导入涉及于它的定理时
Lean 都会产生严重的警告。尽管如此,
它在逐步构建长证明时十分有用。
在从上到下书写证明的时候
你可以用 sorry 来填充子证明:
请先确保 Lean 接受所有的 sorry,
否则意味着有一些错误需要被纠正;然后再回过头,
将每个 sorry替换为实际的证明,直至一切不剩。
还有一个有用的技巧:你可以使用下划线 _ 而非 sorry 作为占位符。
前面提到 _ 会告诉 Lean 参数是隐式的,且应被自动填充。
如果 Lean 试图这样做但失败了,
那么它将会
返回一条错误信息“不知道如何合成占位符”
(don’t know how to synthesize placeholder),并
附加上
它所期望的项的类型,以及
语境中所有可用的所有对象和假设。
换句话说,对于每一个未求解的占位符
Lean 都会报告需要在该点被填充的子目标。
你可以通过逐步填充这些占位符来完成一个证明。
作为参考,我们取上述列表中的两个命题进行示范证明。
| |
3.7. 练习 Exercises
证明下述等式——用真实证明取代 sorry 占位符。
| |
下面的这些需要用到经典逻辑。
| |
最后,尝试不用经典逻辑证明 ¬(p ↔ ¬p) 。
索引 Index
术语
ID 使用 term:<中文术语>。
- Curry-Howard 同构 Curry-Howard Isomorphism
- 命题即类型 Propositions-as-Types
- 占据 Inhabited
- 证明无关性 Proof Irrelevance
- 表达式即证明 Expressions-as-Proofs
- 不可还原的 Irreducible
- 解析器
- 繁饰器
- 结构体 Structure
- 匿名构造子表示法 Anonymous Constructor
- 投影 Projection
- 箭头引入 Arrow-Introduction
- 箭头消去 Arrow-Elimination,又称肯定前件 MP,Modus Ponens
- 合取引入 And-Introduction
- 合取消去 And-Elimination
- 析取引入 Or-Introduction
- 析取消去 Or-Elimination
- 谬误消去 False-Elimination,又称爆炸原理 Principle of Explosion 或 Ex Falso
- 肯定引入 True-Introduction
- 排中律 EM,Excluded Middle
- 双重否定消去规则 DNE,Double-Negation Elimination
- 理发师悖论 Barber Paradox
语法
ID 使用 synt:<关键字>。
- 语法
axiom ... : ... - 语法
#print ... - 语法
⟨...⟩ - 语法
theorem ... := ... - 语法
example ... := ... - 语法
show ... from ... - 语法
have ... := ... - 语法
suffices ... from ... - 策略
sorry
代码块
ID 使用 S<小节>.code<编号>。
S03-01-code01.lean:一些逻辑命题的例子S03-01-code02.lean:创建类型ProofS03-01-code03.lean:创建公理modus_ponensS03-01-code04.lean:创建公理implies_introS03-02-code01.lean:创建定理p → q → p(使用两次implies_intro)S03-02-code02.lean:打印定理p → q → pS03-02-code03.lean:创建定理p → q → p(使用show)S03-02-code04.lean:创建定理p → q → p(第二种形式)S03-02-code05.lean:套用定理p → q → pS03-02-code06.lean:创建公理False以破坏逻辑一致性S03-02-code07.lean:创建定理p → q → p(使用隐式参数)S03-02-code08.lean:创建定理p → q → p(使用隐式参数,第二种形式)S03-02-code09.lean:创建定理p → q → p(使用隐式变量)S03-02-code10.lean:套用定理p → q → p(使用显示变量)S03-02-code11.lean:创建定理(p → q) → (q → r) → (p → r)S03-03-code01.lean:一些命题连结词S03-03-01-code01.lean:创建例子 合取引入S03-03-01-code02.lean:创建例子 合取消去S03-03-01-code03.lean:创建例子p ∧ q → q ∧ p(使用合取引入与合取消去)S03-03-01-code04.lean:介绍匿名构造子S03-03-01-code05.lean:介绍投影S03-03-01-code06.lean:创建例子p ∧ q → q ∧ p(使用合取引入(匿名构造子)与合取消去(投影))S03-03-01-code07.lean:创建例子(p ∧ q) → (q ∧ p ∧ q)(使用嵌套匿名构造子(合取引入))S03-03-02-code01.lean:创建例子 析取引入S03-03-02-code02.lean:创建例子p ∨ q → q ∨ p(使用析取引入和析取消去)S03-03-02-code03.lean:创建例子p ∨ q → q ∨ p(使用析取引入(Or.inl、Or.inr)和析取消去)S03-03-02-code04.lean:创建例子p ∨ q → q ∨ p(使用析取引入(Or.inl、Or.inr)和析取消去(投影))S03-03-03-code01.lean:创建例子(p → q) → (¬q → ¬p)(使用否定引入和否定消去)S03-03-03-code02.lean:创建例子(p ∧ ¬p) → q(使用否定消去和谬误消去)S03-03-03-code03.lean:创建例子(¬p ∧ q) → (q → p) → r(使用absurd代替否定消去和谬误消去)S03-03-04-code01.lean:创建定理p ∧ q ↔ q ∧ p(使用等价引入)S03-03-04-code02.lean:创建定理p ∧ q ↔ q ∧ p(使用等价引入(匿名构造子)与等价消去(投影))S03-04-code01.lean:创建例子p ∧ q → q ∧ p(使用have)S03-04-code02.lean:创建例子p ∧ q → q ∧ p(使用suffices)S03-05-code01.lean:检查公理em p : p ∨ ¬p(使用经典逻辑)S03-05-code02.lean:创建定理dne : ¬¬p → p(使用经典逻辑的em)S03-05-code03.lean:创建例子dne : ¬¬p → p(使用经典逻辑的byCases(相当于em))S03-05-code04.lean:创建例子dne : ¬¬p → p(使用经典逻辑的byContradiction(相当于dne))S03-05-code05.lean:创建例子¬(p ∧ q) → (¬p ∨ ¬q)
练习
ID 使用 exer<编号>。
交换律:
结合律:
分配律:
其他性质:
(p → (q → r)) ↔ (p ∧ q → r)((p ∨ q) → r) ↔ (p → r) ∧ (q → r)¬(p ∨ q) ↔ ¬p ∧ ¬q¬p ∨ ¬q → ¬(p ∧ q)¬(p ∧ ¬p)p ∧ ¬q → ¬(p → q)¬p → (p → q)(¬p ∨ q) → (p → q)p ∨ False ↔ pp ∧ False ↔ False¬(p ↔ ¬p)(p → q) → (¬q → ¬p)
依赖经典逻辑推理的例子:
微信