多个列表的归纳证明
Proof by induction with multiple lists
我正在关注 Coursera 上的 Scala 函数式编程讲座,在视频 5.7 的结尾,Martin Odersky 要求通过归纳法证明以下等式的正确性:
(xs ++ ys) map f = (xs map f) ++ (ys map f)
当涉及多个列表时,如何通过归纳法处理证明?
我已经检查了 xs 为 Nil 和 ys 为 Nil 的基本情况。
我已经通过归纳法证明了当 xs 被 x::xs 代替时方程成立,但是我们是否还需要检查 ys 被 y::ys 代替的方程?
在那种情况下(不会过多破坏练习...无论如何都不会评分)你如何处理:(xs ++ (y::ys)) map f
?
这是我在类似示例中使用的方法,以证明
(xs ++ ys).reverse = ys.reverse ++ xs.reverse
证明(省略基本情况,以及简单的 x::xs 情况):
(xs ++ (y::ys)).reverse
= (xs ++ (List(y) ++ ys)).reverse //y::ys = List(y) ++ ys
= ((xs ++ List(y)) ++ ys).reverse //concat associativity
= ys.reverse ++ (xs ++ List(y)).reverse //by induction hypothesis (proven with x::xs)
= ys.reverse ++ List(y).reverse ++ xs.reverse //by induction hypothesis
= ys.reverse ++ (y::Nil).reverse ++ xs.reverse //List(y) = y :: Nil
= ys.reverse ++ Nil.reverse ++ List(y) ++ xs.reverse //reverse definition
= (ys.reverse ++ List(y)) ++ xs.reverse //reverse on Nil (base case)
= (y :: ys).reverse ++ xs.reverse //reverse definition
这样对吗?
正如@Phil 的评论所说,首先要很好地理解方法 ++
和 ::
在列表上的作用,更好的方法是 documentation
如何证明列表程序的性质?
答案是通过结构归纳!
通过结构归纳证明列表 属性 P(xs) 的证明规则:
P(无)(基本情况)
对于所有 x,xs:P(xs) => P(x::xs)(归纳步骤)
对于所有 xs : P(xs)(结果)
归纳步骤中的P(xs)称为归纳假设
因为唯一重要的是 xs,ys 是固定长度为 l 的适当列表,在证明 xs 之后你可以证明 ys,或者看到它是可交换的
那么让我们应用归纳法和函数的定义
P(xs): (xs ++ ys) 映射 f = (xs 映射 f) ++ (ys 映射 f)
我们用 nil 代替 xs 的基本情况
(nil ++ ys) map f [definition of ++ ]
ys map f on the other hand
(xs map f) ++ (ys map p) [apply map over NIL]
(NIL) ++ (ys map p) [definition pf ++]
ys map p
归纳步骤
((x::xs) ++ ys) map f [definition ++]
(x:: (xs ++ ys)) map f [definition map]
f(x) :: ((xs ++ ys) map f) [induction hypothesis]
f(x) :: ((xs map f) ++ (ys map f)) [definition ++]
(f(x) :: (xs map f)) ++ (ys map f) [definition map]
(x::xs) map f ++ ys map f
q.e.d
例如 scala 工作中的另一个案例 sheet
import scala.util.Random
// P : length ( append(as,bs) )) = length ( as ) + length (bs)
def length[T](as: List[T]): Int = as match {
case Nil => 0
case _::xs => 1 + length(xs)
}
def append[T](as: List[T], bs: List[T]): List[T] = as match {
case Nil => bs
case x :: xs => x :: append(xs, bs)
}
// base case we substitute Nil for as in P
val a:List[Int] = Nil
val n = 10
val b:List[Int] = Seq.fill(n)(Random.nextInt).toList
length((append(a,b)))
length(a)
length(b)
进口scala.util.Random
length: length[T](val as: List[T]) => Int
append: append[T](val as: List[T],val bs: List[T]) => List[T]
a: List[Int] = List()
n: Int = 10
b: List[Int] = List(1168053950, 922397949, -1884264936, 869558369, -165728826, -1052466354, -1696038881, 246666877, 1673332480, -975585734)
res0: Int = 10
res1: Int = 0
res2: Int = 10
here 你可以找到更多例子
属性 涉及多个列表,但 ++
仅递归其左侧参数。这暗示你可以通过对左边的论证进行归纳来证明。通常,在证明关于某个递归函数的命题时,您尝试的第一件事是对函数递归的相同参数进行归纳。
我给你举个例子:
声明:(xs ++ ys) map f
= (xs map f) ++ (ys map f)
证明:通过对xs
.
的归纳
基本情况:xs
= Nil
lhs = (Nil ++ ys) map f
= ys map f
(根据++
的定义)
rhs = (Nil map f) ++ (ys map f)
= Nil ++ ys map f
= ys map f
(由map
定义,然后++
定义)
- 因此lhs=rhs
归纳案例:xs
= z :: zs
- 假设:
(zs ++ ys) map f
= (zs map f) ++ (ys map f)
- 目标:
((z :: zs) ++ ys) map f
= ((z :: zs) map f) ++ (ys map f)
lhs = (z :: (zs ++ ys)) map f
= f(z) :: ((zs ++ ys) map f)
(1)
(根据map
的定义)
rhs = ((z :: zs) map f) ++ (ys map f)
= (f(z) :: (zs map f)) ++ (ys map f)
(根据map
的定义)
依次,rhs=f(z) :: ((zs map f) ++ (ys map f))
(2)
(根据++
的定义)
- 来自假设,(1)和(2),我们已经证明了目标 .
因此,我们已经证明了 xs
、ys
和 f
的说法是真实的。
我正在关注 Coursera 上的 Scala 函数式编程讲座,在视频 5.7 的结尾,Martin Odersky 要求通过归纳法证明以下等式的正确性:
(xs ++ ys) map f = (xs map f) ++ (ys map f)
当涉及多个列表时,如何通过归纳法处理证明?
我已经检查了 xs 为 Nil 和 ys 为 Nil 的基本情况。 我已经通过归纳法证明了当 xs 被 x::xs 代替时方程成立,但是我们是否还需要检查 ys 被 y::ys 代替的方程?
在那种情况下(不会过多破坏练习...无论如何都不会评分)你如何处理:(xs ++ (y::ys)) map f
?
这是我在类似示例中使用的方法,以证明
(xs ++ ys).reverse = ys.reverse ++ xs.reverse
证明(省略基本情况,以及简单的 x::xs 情况):
(xs ++ (y::ys)).reverse
= (xs ++ (List(y) ++ ys)).reverse //y::ys = List(y) ++ ys
= ((xs ++ List(y)) ++ ys).reverse //concat associativity
= ys.reverse ++ (xs ++ List(y)).reverse //by induction hypothesis (proven with x::xs)
= ys.reverse ++ List(y).reverse ++ xs.reverse //by induction hypothesis
= ys.reverse ++ (y::Nil).reverse ++ xs.reverse //List(y) = y :: Nil
= ys.reverse ++ Nil.reverse ++ List(y) ++ xs.reverse //reverse definition
= (ys.reverse ++ List(y)) ++ xs.reverse //reverse on Nil (base case)
= (y :: ys).reverse ++ xs.reverse //reverse definition
这样对吗?
正如@Phil 的评论所说,首先要很好地理解方法 ++
和 ::
在列表上的作用,更好的方法是 documentation
如何证明列表程序的性质? 答案是通过结构归纳! 通过结构归纳证明列表 属性 P(xs) 的证明规则:
P(无)(基本情况) 对于所有 x,xs:P(xs) => P(x::xs)(归纳步骤)
对于所有 xs : P(xs)(结果)
归纳步骤中的P(xs)称为归纳假设
因为唯一重要的是 xs,ys 是固定长度为 l 的适当列表,在证明 xs 之后你可以证明 ys,或者看到它是可交换的
那么让我们应用归纳法和函数的定义
P(xs): (xs ++ ys) 映射 f = (xs 映射 f) ++ (ys 映射 f)
我们用 nil 代替 xs 的基本情况
(nil ++ ys) map f [definition of ++ ]
ys map f on the other hand
(xs map f) ++ (ys map p) [apply map over NIL]
(NIL) ++ (ys map p) [definition pf ++]
ys map p
归纳步骤
((x::xs) ++ ys) map f [definition ++]
(x:: (xs ++ ys)) map f [definition map]
f(x) :: ((xs ++ ys) map f) [induction hypothesis]
f(x) :: ((xs map f) ++ (ys map f)) [definition ++]
(f(x) :: (xs map f)) ++ (ys map f) [definition map]
(x::xs) map f ++ ys map f
q.e.d
例如 scala 工作中的另一个案例 sheet
import scala.util.Random
// P : length ( append(as,bs) )) = length ( as ) + length (bs)
def length[T](as: List[T]): Int = as match {
case Nil => 0
case _::xs => 1 + length(xs)
}
def append[T](as: List[T], bs: List[T]): List[T] = as match {
case Nil => bs
case x :: xs => x :: append(xs, bs)
}
// base case we substitute Nil for as in P
val a:List[Int] = Nil
val n = 10
val b:List[Int] = Seq.fill(n)(Random.nextInt).toList
length((append(a,b)))
length(a)
length(b)
进口scala.util.Random
length: length[T](val as: List[T]) => Int
append: append[T](val as: List[T],val bs: List[T]) => List[T]
a: List[Int] = List()
n: Int = 10
b: List[Int] = List(1168053950, 922397949, -1884264936, 869558369, -165728826, -1052466354, -1696038881, 246666877, 1673332480, -975585734)
res0: Int = 10
res1: Int = 0
res2: Int = 10
here 你可以找到更多例子
属性 涉及多个列表,但 ++
仅递归其左侧参数。这暗示你可以通过对左边的论证进行归纳来证明。通常,在证明关于某个递归函数的命题时,您尝试的第一件事是对函数递归的相同参数进行归纳。
我给你举个例子:
声明:(xs ++ ys) map f
= (xs map f) ++ (ys map f)
证明:通过对xs
.
基本情况:
xs
=Nil
lhs =
(Nil ++ ys) map f
=ys map f
(根据
++
的定义)rhs =
(Nil map f) ++ (ys map f)
=Nil ++ ys map f
=ys map f
(由
map
定义,然后++
定义)- 因此lhs=rhs
归纳案例:
xs
=z :: zs
- 假设:
(zs ++ ys) map f
=(zs map f) ++ (ys map f)
- 目标:
((z :: zs) ++ ys) map f
=((z :: zs) map f) ++ (ys map f)
lhs =
(z :: (zs ++ ys)) map f
=f(z) :: ((zs ++ ys) map f)
(1)(根据
map
的定义)rhs =
((z :: zs) map f) ++ (ys map f)
=(f(z) :: (zs map f)) ++ (ys map f)
(根据
map
的定义)依次,rhs=
f(z) :: ((zs map f) ++ (ys map f))
(2)(根据
++
的定义)- 来自假设,(1)和(2),我们已经证明了目标 .
- 假设:
因此,我们已经证明了 xs
、ys
和 f
的说法是真实的。