在精益(Lean)中对定理进行证明(第二章)

2.依赖型理论

依赖类型理论是一种强大而富有表现力的语言,允许我们表达复杂的数学断言,编写复杂的硬件和软件规范,并以自然和统一的方式对这两者进行推理。 精益是基于一种称为归纳建构微积分的依赖型理论,具有可累积的非累积宇宙和归纳类型的层次结构。 到本章结束时,您将了解这意味着什么。

2.1 简单类型理论

作为数学的基础,集合论有一个相当吸引人的简单本体论。 一切都是一组,包括数字,函数,三角形,随机过程和黎曼流形。 一个值得注意的事实是,人们可以从少数描述一些基本集合理论结构的公理构建一个丰富的数学世界。

但是出于许多目的,包括正式定理证明,最好有一个基础设施来帮助我们管理和跟踪我们正在使用的各种数学对象。 “类型理论”的名称源于每个表达式都具有关联类型的事实。 例如,在给定的上下文中,x + 0可以表示自然数,f可以表示对自然数的函数。

以下是我们如何在Lean中声明对象并检查其类型的一些示例。

import standard
open bool nat

/- declare some constants -/

constant m : nat        -- m is a natural number
constant n : nat
constants b1 b2 : bool  -- declare two constants at once

/- check their types -/

check m            -- output: nat
check n
check n + 0        -- nat    
check m * (n + 0)  -- nat
check b1           -- bool
check b1 && b2     -- "&&" is boolean and
check b1 || b2     -- boolean or
check tt           -- boolean "true"

第一个命令,import standard,告诉Lean我们打算使用标准库。下一个命令open bool nat告诉Lean我们将使用来自布尔理论和自然数理论的常数,事实和符号。在技​​术方面,bool和nat是命名空间;稍后您将了解更多相关信息。为了缩短示例,我们通常会隐藏相关导入,如果在前面的示例中已经导入。

/  - 和 -  /注释表明下一行是精益忽略的注释块。类似地,两个破折号表示该行的其余部分包含也被忽略的注释。注释块可以嵌套,从而可以“注释掉”代码块,就像在许多编程语言中一样。

constant和constants命令将新的常量符号引入工作环境,check命令要求Lean报告其类型。你应该测试一下,然后尝试输入你自己的一些例子。以这种方式声明新对象是试验系统的好方法,但最终不可取:精益是一个基础系统,也就是说,它为我们提供了强大的机制来定义我们需要的所有数学对象,而不是简单地将它们假装到系统中。我们将在后面的章节中探讨这些机制。

简单类型理论的强大之处在于可以构建其他类型的新类型。例如,如果A和B是类型,则A→B表示从A到B的函数类型,A×B表示笛卡尔积,即,由A元素和B元素组成的有序对的类型。

open prod   -- makes notation for the product available

constants m n : nat

constant f : nat → nat           -- type the arrow as "\to" or "\r"
constant f' : nat -> nat         -- alternative ASCII notation
constant f'' : ℕ → ℕ             -- \nat is alternative notation for nat
constant p : nat × nat           -- type the product as "\times"
constant q : prod nat nat        -- alternative notation
constant g : nat → nat → nat
constant g' : nat → (nat → nat)  -- has the same type as g!
constant h : nat × nat → nat

constant F : (nat → nat) → nat   -- a "functional"

check f               -- ℕ → ℕ
check f n             -- ℕ
check g m n           -- ℕ
check g m             -- ℕ → ℕ
check pair m n        -- ℕ × ℕ
check pr1 p           -- ℕ
check pr2 p           -- ℕ
check pr1 (pair m n)  -- ℕ
check pair (pr1 p) n  -- ℕ × ℕ
check F f             -- ℕ

符号ℕ是nat的符号;您可以输入\ nat输入它。还有一些事情需要注意。首先,将函数f应用于值x表示为f x。其次,在写类型表达式时,箭头与右侧相关联;例如,g的类型是nat→(nat→nat)。因此,我们可以将g视为一个函数,它接受自然数并返回另一个采用自然数并返回自然数的函数。在类型理论中,这通常比将g作为以一对自然数作为输入的函数编写更方便,并返回自然数作为输出。例如,它允许我们“部分应用”函数g。上面的例子表明g m的类型为nat→nat,即“等待”第二个参数n的函数,然后返回g m n。采用nat×nat→nat类型的函数h和“重新定义”它看起来像g是一个称为currying的过程,我们将回到下面。

到目前为止,您可能还猜到,在精益中,对m n表示有序的m和n对,如果p是一对,则pr1 p和pr2 p表示两个投影。

2.2 作为对象的类型

精益依赖类型理论扩展简单类型理论的一种方式是类型本身 - 像nat和bool这样的实体 - 是一等公民,也就是说它们本身就是研究对象。 对于那种情况,他们每个人也必须有一个类型。

check nat               -- Type₁
check bool              -- Type₁
check nat → bool        -- Type₁
check nat × bool        -- Type₁
check nat → nat         -- ...
check nat × nat → nat
check nat → nat → nat
check nat → (nat → nat)
check nat → nat → bool
check (nat → nat) → nat

我们看到上面的每个表达式都是Type 1类型的对象。 我们马上解释下标1。 我们还可以为类型声明新的常量和构造函数: 

constants A B : Type
constant F : Type → Type
constant G : Type → Type → Type

check A        -- Type
check F A      -- Type
check F nat    -- Type
check G A      -- Type → Type
check G A B    -- Type
check G A nat  -- Type

实际上,我们已经看到类型→类型→类型的函数的示例,即笛卡尔积。 

constants A B : Type

check prod           -- Type → Type → Type
check prod A         -- Type → Type
check prod A B       -- Type
check prod nat nat   -- Type₁

这是另一个例子:给定任何类型A,类型列表A表示类型A的元素列表的类型。

import data.list
open list

constant A : Type

check list      -- Type → Type
check list A    -- Type
check list nat  -- Type₁

我们将看到将类型构造函数视为普通数学函数实例的能力是依赖类型理论的强大特征。

对于那些对集合理论基础更为熟悉的人来说,将类型视为集合可能会有所帮助,在这种情况下,类型的元素只是集合的元素。 但附近有潜伏的圆形。 类型本身是一个像nat的表达式; 如果nat有一个类型,那么Type不应该有类型吗?

check Type      -- Type

猜你喜欢

转载自blog.csdn.net/cmmsdwj/article/details/85230506
今日推荐