forked from epfl-lara/stainless
-
Notifications
You must be signed in to change notification settings - Fork 0
/
InnerClasses4.scala
66 lines (53 loc) · 1.62 KB
/
InnerClasses4.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import stainless.lang._
import stainless.proof._
import stainless.collection._
import stainless.annotation._
object InnerClasses4 {
abstract class Semigroup[A] {
def append(l: A, r: A): A
@law
def law_associativity(x: A, y: A, z: A): Boolean = {
append(append(x, y), z) == append(x, append(y, z))
}
}
abstract class Monoid[A] extends Semigroup[A] {
def empty: A
@law
def law_leftIdentity(x: A): Boolean = {
append(empty, x) == x
}
@law
def law_rightIdentity(x: A): Boolean = {
append(x, empty) == x
}
}
@induct
def listAppendIsAssociative[A](x: List[A], y: List[A], z: List[A]): Boolean = {
(x ++ y) ++ z == x ++ (y ++ z)
}.holds
implicit def listMonoid[A](implicit ev: Monoid[A]): Monoid[List[A]] = new Monoid[List[A]] {
def empty: List[A] = Nil()
def append(l: List[A], r: List[A]) = l ++ r
override def law_associativity(x: List[A], y: List[A], z: List[A]): Boolean = {
super.law_associativity(x, y, z).because(listAppendIsAssociative(x, y, z))
}
}
case class Sum(get: BigInt)
object Sum {
implicit def sumMonoid: Monoid[Sum] = new Monoid[Sum] {
def empty: Sum = Sum(0)
def append(a: Sum, b: Sum): Sum = Sum(a.get + b.get)
}
}
case class Prod(get: BigInt)
object Prod {
implicit def prodMonoid: Monoid[Prod] = new Monoid[Prod] {
def empty: Prod = Prod(1)
def append(a: Prod, b: Prod): Prod = Prod(a.get * b.get)
}
}
def foldMap[A, M](xs: List[A])(f: A => M)(implicit ev: Monoid[M]): M = xs match {
case Nil() => ev.empty
case Cons(y, ys) => ev.append(f(y), foldMap(ys)(f))
}
}