Lean 列表操作与证明
介绍
在Lean中,列表(List)是一种基本的数据结构,用于存储一系列有序的元素。列表操作是函数式编程中的核心概念之一,而证明列表的性质则是Lean中形式化验证的重要组成部分。本文将逐步讲解如何在Lean中操作列表,并通过实际案例展示如何证明与列表相关的性质。
列表的基本操作
创建列表
在Lean中,列表可以通过以下方式创建:
#check [1, 2, 3] -- List ℕ
这里,[1, 2, 3]
是一个包含三个自然数的列表,类型为 List ℕ
。
列表的拼接
列表可以通过 ++
操作符进行拼接:
#check [1, 2] ++ [3, 4] -- [1, 2, 3, 4]
列表的长度
使用 List.length
函数可以获取列表的长度:
#check List.length [1, 2, 3] -- 3
列表的映射
List.map
函数可以将一个函数应用到列表的每个元素上:
#check List.map (λ x => x + 1) [1, 2, 3] -- [2, 3, 4]
列表的递归定义
在Lean中,列表是通过递归定义的。一个列表要么是空的(List.nil
),要么是一个元素与另一个列表的组合(List.cons
)。例如:
#check List.nil -- List ℕ
#check List.cons 1 (List.cons 2 List.nil) -- [1, 2]
列表的证明
证明列表的长度
我们可以 通过递归来证明列表的长度性质。例如,证明列表拼接后的长度等于两个列表长度之和:
theorem length_append : ∀ (l1 l2 : List ℕ), List.length (l1 ++ l2) = List.length l1 + List.length l2 :=
begin
intros l1 l2,
induction l1,
{ simp, },
{ simp [l1_ih], }
end
在这个证明中,我们使用了归纳法来证明对于任意两个列表 l1
和 l2
,拼接后的列表长度等于 l1
和 l2
长度之和。
证明列表的映射
我们可以证明 List.map
函数的性质。例如,证明 List.map
保持列表长度不变:
theorem length_map : ∀ (f : ℕ → ℕ) (l : List ℕ), List.length (List.map f l) = List.length l :=
begin
intros f l,
induction l,
{ simp, },
{ simp [l_ih], }
end
这个证明展示了 List.map
函数不会改变列表的长度。
实际案例
案例:反转列表
我们可以定义一个函数来反转列表,并证明反转后的列表长度不变:
def reverse : List ℕ → List ℕ
| [] := []
| (h :: t) := reverse t ++ [h]
theorem length_reverse : ∀ (l : List ℕ), List.length (reverse l) = List.length l :=
begin
intros l,
induction l,
{ simp [reverse], },
{ simp [reverse, l_ih], }
end
在这个案例中,我们定义了一个 reverse
函数来反转列表,并通过归纳法证明了反转后的列表长度与原列表相同。
总结
本文介绍了Lean中列表的基本操作和证明技巧。我们学习了如何创建、拼接、映射列表,并通过递归和归纳法证明了列表的一些基本性质。通过这些示例,初学者可以逐步掌握Lean中的列表操作与证明。