通过多个列表的归纳证明

时间:2015-05-22 23:25:24

标签: scala functional-programming induction proof-of-correctness equational-reasoning

我正在关注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

这是对的吗?

2 个答案:

答案 0 :(得分:4)

该属性涉及多个列表,但++仅对其左侧参数进行递归。这是一个提示,你可以通过归纳证明左边的论点。一般来说,当证明关于某些递归函数的命题时,你尝试的第一件事是引入函数在上递归的相同参数。

我会为你做一个例子:

声明(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) ,我们已经证明 目标

因此,我们已经证明声明是xsysf无效的声明。

答案 1 :(得分:0)

正如@Phil的评论所说,首先是对++::方法在列表中所做的工作的一个很好的理解,更好的方法是documentation

我们如何证明列表程序的属性? 答案是结构感应! 通过结构归纳证明列表属性P(xs)的证明规则:

P(无)(基本情况)  对于所有x,xs:P(xs)=> P(x :: xs)(归纳步骤)

表示所有xs:P(xs)(后果)

诱导步骤中的P(xs)称为诱导假设

因为唯一重要的是xs,ys用lenght l修复正确的List,在证明xs后你可以证明ys,或者看到它是可交换的

因此,让我们应用归纳法和函数的定义

P(xs):( xs ++ ys)map f =(xs map f)++(ys map f)

基本情况我们将xs替换为nil

(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工作表中的另一个案例

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您可以找到更多示例