90 lines
2.5 KiB
Scala
90 lines
2.5 KiB
Scala
package green.thisfieldwas.embracingnondeterminism.stdlib
|
|
|
|
import green.thisfieldwas.embracingnondeterminism.data.{Monoid, MonoidLaws, SemigroupLaws}
|
|
import green.thisfieldwas.embracingnondeterminism.util._
|
|
import org.scalacheck.Arbitrary.arbitrary
|
|
import org.scalacheck.{Arbitrary, Gen}
|
|
|
|
/** Proves that Scala's Set conforms to the following typeclasses:
|
|
* - Functor
|
|
* - Monad
|
|
* - Semigroup
|
|
* - Monoid
|
|
*/
|
|
class SetSpec extends Laws with SemigroupLaws with MonoidLaws {
|
|
|
|
property("Set.map() preserves identity functions") {
|
|
forAll(arbitrary[Set[Int]]) { fa =>
|
|
fa.map(identity) mustBe identity(fa)
|
|
}
|
|
}
|
|
|
|
property("Set.map() preserves function composition") {
|
|
forAll(for {
|
|
fa <- arbitrary[Set[Double]]
|
|
f <- arbitrary[Double => String]
|
|
g <- arbitrary[String => Int]
|
|
} yield (fa, f, g)) { case (fa, f, g) =>
|
|
fa.map(g compose f) mustBe fa.map(f).map(g)
|
|
}
|
|
}
|
|
|
|
property(s"Set.flatMap() preserves left identity") {
|
|
forAll(for {
|
|
a <- arbitrary[Int]
|
|
h <- arbitrary[Int => Set[String]]
|
|
} yield (a, h)) { case (a, h) =>
|
|
val leftIdentity = (x: Int) => Set(x).flatMap(h)
|
|
leftIdentity(a) mustBe h(a)
|
|
}
|
|
}
|
|
|
|
property(s"Set.flatMap() preserves right identity") {
|
|
forAll(for {
|
|
a <- arbitrary[Int]
|
|
h <- arbitrary[Int => Set[String]]
|
|
} yield (a, h)) { case (a, h) =>
|
|
val rightIdentity = h(_: Int).flatMap(Set(_))
|
|
rightIdentity(a) mustBe h(a)
|
|
}
|
|
}
|
|
|
|
property(s"Set.flatMap() is associative") {
|
|
forAll(for {
|
|
a <- arbitrary[Double]
|
|
f <- arbitrary[Double => Set[String]]
|
|
g <- arbitrary[String => Set[Int]]
|
|
h <- arbitrary[Int => Set[Boolean]]
|
|
} yield (a, f, g, h)) { case (a, f, g, h) =>
|
|
val assocLeft = f(_: Double).flatMap(g).flatMap(h)
|
|
val assocRight = f(_: Double).flatMap(g(_).flatMap(h))
|
|
assocLeft(a) mustBe assocRight(a)
|
|
}
|
|
}
|
|
|
|
implicit def arbitrarySet[A: Arbitrary]: Arbitrary[Set[A]] = Arbitrary {
|
|
for {
|
|
length <- Gen.sized(Gen.choose(0, _))
|
|
set <- Gen.listOfN(length, arbitrary[A]).map(_.toSet)
|
|
} yield set
|
|
}
|
|
|
|
/** Set forms a Semigroup under union and a Monoid with an identity value of
|
|
* an empty Set().
|
|
*
|
|
* @tparam A
|
|
* Any type held by the Set.
|
|
* @return
|
|
* The Semigroup instance for Set.
|
|
*/
|
|
implicit def setMonoid[A]: Monoid[Set[A]] = new Monoid[Set[A]] {
|
|
|
|
override def empty: Set[A] = Set()
|
|
|
|
override def combine(left: Set[A], right: Set[A]): Set[A] = left.union(right)
|
|
}
|
|
|
|
checkSemigroupLaws[Set[Int]]()
|
|
checkMonoidLaws[Set[Int]]()
|
|
}
|