FlatMap.scala [raw]
/* Copyright 2009-2016 EPFL, Lausanne */
import stainless.lang._
import stainless.proof._
import stainless.collection._
object FlatMap {
def append[T](l1: List[T], l2: List[T]): List[T] = l1 match {
case Cons(head, tail) => Cons(head, append(tail, l2))
case Nil() => l2
}
def associative_append_lemma[T](l1: List[T], l2: List[T], l3: List[T]): Boolean = {
append(append(l1, l2), l3) == append(l1, append(l2, l3))
}
def associative_append_lemma_induct[T](l1: List[T], l2: List[T], l3: List[T]): Boolean = {
l1 match {
case Nil() => associative_append_lemma(l1, l2, l3)
case Cons(head, tail) => associative_append_lemma(l1, l2, l3) because associative_append_lemma_induct(tail, l2, l3)
}
}.holds
def flatMap[T,U](list: List[T], f: T => List[U]): List[U] = list match {
case Cons(head, tail) => append(f(head), flatMap(tail, f))
case Nil() => Nil()
}
def associative_lemma[T,U,V](list: List[T], f: T => List[U], g: U => List[V]): Boolean = {
flatMap(flatMap(list, f), g) == flatMap(list, (x: T) => flatMap(f(x), g))
}
def associative_lemma_induct[T,U,V](list: List[T], flist: List[U], glist: List[V], f: T => List[U], g: U => List[V]): Boolean = {
associative_lemma(list, f, g) because {
append(glist, flatMap(append(flist, flatMap(list, f)), g)) == append(append(glist, flatMap(flist, g)), flatMap(list, (x: T) => flatMap(f(x), g))) because
(glist match {
case Cons(ghead, gtail) =>
associative_lemma_induct(list, flist, gtail, f, g)
case Nil() => flist match {
case Cons(fhead, ftail) =>
associative_lemma_induct(list, ftail, g(fhead), f, g)
case Nil() => list match {
case Cons(head, tail) => associative_lemma_induct(tail, f(head), Nil(), f, g)
case Nil() => true
}
}
})
}
}.holds
}
back