-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Get the relevant bits of algebra.laws ported over.
There are a few things here: 1. Many of algebra's interesting laws apply to rings/lattices. 2. We introduce a (laws-only) dependency on catalysts-platform. 3. Unlike Cats, we'll run the tests in kernel-laws' tests.
- Loading branch information
Showing
8 changed files
with
456 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
kernel-laws/src/main/scala/cats/kernel/laws/BaseLaws.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package cats.kernel.laws | ||
|
||
import cats.kernel._ | ||
|
||
import org.typelevel.discipline.Laws | ||
|
||
import org.scalacheck.{Arbitrary, Prop} | ||
|
||
object BaseLaws { | ||
def apply[A : Eq : Arbitrary] = new BaseLaws[A] { | ||
def Equ = Eq[A] | ||
def Arb = implicitly[Arbitrary[A]] | ||
} | ||
} | ||
|
||
trait BaseLaws[A] extends Laws { | ||
|
||
implicit def Equ: Eq[A] | ||
implicit def Arb: Arbitrary[A] | ||
|
||
class BaseRuleSet( | ||
val name: String, | ||
val parent: Option[RuleSet], | ||
val bases: Seq[(String, Laws#RuleSet)], | ||
val props: (String, Prop)* | ||
) extends RuleSet with HasOneParent | ||
} |
12 changes: 12 additions & 0 deletions
12
kernel-laws/src/main/scala/cats/kernel/laws/CheckSupport.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// package cats.kernel.laws | ||
// | ||
// /** | ||
// * This object contains Arbitrary instances for types defined in | ||
// * cats.kernel.std, as well as anything else we'd like to import to assist | ||
// * in running ScalaCheck tests. | ||
// * | ||
// * (Since cats.kernel-std has no dependencies, its types can't define | ||
// * Arbitrary instances in companions.) | ||
// */ | ||
// object CheckSupport { | ||
// } |
142 changes: 142 additions & 0 deletions
142
kernel-laws/src/main/scala/cats/kernel/laws/GroupLaws.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
package cats.kernel.laws | ||
|
||
import cats.kernel._ | ||
|
||
import org.typelevel.discipline.Laws | ||
|
||
import org.scalacheck.{Arbitrary, Prop} | ||
import org.scalacheck.Prop._ | ||
|
||
object GroupLaws { | ||
def apply[A : Eq : Arbitrary] = new GroupLaws[A] { | ||
def Equ = Eq[A] | ||
def Arb = implicitly[Arbitrary[A]] | ||
} | ||
} | ||
|
||
trait GroupLaws[A] extends Laws { | ||
|
||
implicit def Equ: Eq[A] | ||
implicit def Arb: Arbitrary[A] | ||
|
||
// groups | ||
|
||
def semigroup(implicit A: Semigroup[A]) = new GroupProperties( | ||
name = "semigroup", | ||
parents = Nil, | ||
Rules.serializable(A), | ||
Rules.associativity(A.combine), | ||
Rules.repeat1("combineN")(A.combineN), | ||
Rules.repeat2("combineN", "|+|")(A.combineN)(A.combine) | ||
) | ||
|
||
def band(implicit A: Band[A]) = new GroupProperties( | ||
name = "band", | ||
parents = List(semigroup), | ||
Rules.idempotence(A.combine), | ||
"isIdempotent" -> Semigroup.isIdempotent[A] | ||
) | ||
|
||
def commutativeSemigroup(implicit A: CommutativeSemigroup[A]) = new GroupProperties( | ||
name = "commutative semigroup", | ||
parents = List(semigroup), | ||
Rules.commutative(A.combine) | ||
) | ||
|
||
def semilattice(implicit A: Semilattice[A]) = new GroupProperties( | ||
name = "semilattice", | ||
parents = List(band, commutativeSemigroup) | ||
) | ||
|
||
def monoid(implicit A: Monoid[A]) = new GroupProperties( | ||
name = "monoid", | ||
parents = List(semigroup), | ||
Rules.leftIdentity(A.empty)(A.combine), | ||
Rules.rightIdentity(A.empty)(A.combine), | ||
Rules.repeat0("combineN", "id", A.empty)(A.combineN), | ||
Rules.collect0("combineAll", "id", A.empty)(A.combineAll), | ||
Rules.isId("isEmpty", A.empty)(A.isEmpty) | ||
) | ||
|
||
def commutativeMonoid(implicit A: CommutativeMonoid[A]) = new GroupProperties( | ||
name = "commutative monoid", | ||
parents = List(monoid, commutativeSemigroup) | ||
) | ||
|
||
def boundedSemilattice(implicit A: BoundedSemilattice[A]) = new GroupProperties( | ||
name = "boundedSemilattice", | ||
parents = List(commutativeMonoid, semilattice) | ||
) | ||
|
||
def group(implicit A: Group[A]) = new GroupProperties( | ||
name = "group", | ||
parents = List(monoid), | ||
Rules.leftInverse(A.empty)(A.combine)(A.inverse), | ||
Rules.rightInverse(A.empty)(A.combine)(A.inverse), | ||
Rules.consistentInverse("remove")(A.remove)(A.combine)(A.inverse) | ||
) | ||
|
||
def commutativeGroup(implicit A: CommutativeGroup[A]) = new GroupProperties( | ||
name = "commutative group", | ||
parents = List(group, commutativeMonoid) | ||
) | ||
|
||
// // additive groups | ||
// | ||
// def additiveSemigroup(implicit A: AdditiveSemigroup[A]) = new AdditiveProperties( | ||
// base = semigroup(A.additive), | ||
// parents = Nil, | ||
// Rules.serializable(A), | ||
// Rules.repeat1("sumN")(A.sumN), | ||
// Rules.repeat2("sumN", "+")(A.sumN)(A.plus) | ||
// ) | ||
// | ||
// def additiveCommutativeSemigroup(implicit A: AdditiveCommutativeSemigroup[A]) = new AdditiveProperties( | ||
// base = commutativeSemigroup(A.additive), | ||
// parents = List(additiveSemigroup) | ||
// ) | ||
// | ||
// def additiveMonoid(implicit A: AdditiveMonoid[A]) = new AdditiveProperties( | ||
// base = monoid(A.additive), | ||
// parents = List(additiveSemigroup), | ||
// Rules.repeat0("sumN", "zero", A.zero)(A.sumN), | ||
// Rules.collect0("sum", "zero", A.zero)(A.sum) | ||
// ) | ||
// | ||
// def additiveCommutativeMonoid(implicit A: AdditiveCommutativeMonoid[A]) = new AdditiveProperties( | ||
// base = commutativeMonoid(A.additive), | ||
// parents = List(additiveMonoid) | ||
// ) | ||
// | ||
// def additiveGroup(implicit A: AdditiveGroup[A]) = new AdditiveProperties( | ||
// base = group(A.additive), | ||
// parents = List(additiveMonoid), | ||
// Rules.consistentInverse("subtract")(A.minus)(A.plus)(A.negate) | ||
// ) | ||
// | ||
// def additiveCommutativeGroup(implicit A: AdditiveCommutativeGroup[A]) = new AdditiveProperties( | ||
// base = commutativeGroup(A.additive), | ||
// parents = List(additiveGroup) | ||
// ) | ||
|
||
|
||
// property classes | ||
|
||
class GroupProperties( | ||
val name: String, | ||
val parents: Seq[GroupProperties], | ||
val props: (String, Prop)* | ||
) extends RuleSet { | ||
val bases = Nil | ||
} | ||
|
||
// class AdditiveProperties( | ||
// val base: GroupProperties, | ||
// val parents: Seq[AdditiveProperties], | ||
// val props: (String, Prop)* | ||
// ) extends RuleSet { | ||
// val name = base.name | ||
// val bases = List("base" -> base) | ||
// } | ||
|
||
} |
14 changes: 14 additions & 0 deletions
14
kernel-laws/src/main/scala/cats/kernel/laws/IsSerializable.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package cats.kernel.laws | ||
|
||
import catalysts.Platform | ||
|
||
import scala.util.DynamicVariable | ||
|
||
/** | ||
* Object with a dynamic variable that allows users to skip the | ||
* serialization tests for certain instances. | ||
*/ | ||
private[laws] object IsSerializable { | ||
val runTests = new DynamicVariable[Boolean](true) | ||
def apply(): Boolean = (!Platform.isJs) && runTests.value | ||
} |
79 changes: 79 additions & 0 deletions
79
kernel-laws/src/main/scala/cats/kernel/laws/OrderLaws.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package cats.kernel | ||
package laws | ||
|
||
import org.typelevel.discipline.Laws | ||
|
||
import org.scalacheck.{Arbitrary, Prop} | ||
import org.scalacheck.Prop._ | ||
|
||
import cats.kernel.std.boolean._ | ||
|
||
object OrderLaws { | ||
def apply[A: Eq: Arbitrary] = new OrderLaws[A] { | ||
def Equ = Eq[A] | ||
def Arb = implicitly[Arbitrary[A]] | ||
} | ||
} | ||
|
||
trait OrderLaws[A] extends Laws { | ||
|
||
implicit def Equ: Eq[A] | ||
implicit def Arb: Arbitrary[A] | ||
|
||
def eqv = new OrderProperties( | ||
name = "eq", | ||
parent = None, | ||
Rules.serializable(Equ), | ||
"reflexitivity-eq" -> forAll { (x: A) => | ||
x ?== x | ||
}, | ||
"symmetry-eq" -> forAll { (x: A, y: A) => | ||
Equ.eqv(x, y) ?== Equ.eqv(y, x) | ||
}, | ||
"antisymmetry-eq" -> forAll { (x: A, y: A, f: A => A) => | ||
!Equ.eqv(x, y) ?|| Equ.eqv(f(x), f(y)) | ||
}, | ||
This comment has been minimized.
Sorry, something went wrong. |
||
"transitivity-eq" -> forAll { (x: A, y: A, z: A) => | ||
!(Equ.eqv(x, y) && Equ.eqv(y, z)) ?|| Equ.eqv(x, z) | ||
} | ||
) | ||
|
||
def partialOrder(implicit A: PartialOrder[A]) = new OrderProperties( | ||
name = "partialOrder", | ||
parent = Some(eqv), | ||
Rules.serializable(A), | ||
"reflexitivity" -> forAll { (x: A) => | ||
x ?<= x | ||
}, | ||
"antisymmetry" -> forAll { (x: A, y: A) => | ||
!(A.lteqv(x, y) && A.lteqv(y, x)) ?|| A.eqv(x, y) | ||
}, | ||
"transitivity" -> forAll { (x: A, y: A, z: A) => | ||
!(A.lteqv(x, y) && A.lteqv(y, z)) ?|| A.lteqv(x, z) | ||
}, | ||
"gteqv" -> forAll { (x: A, y: A) => | ||
A.lteqv(x, y) ?== A.gteqv(y, x) | ||
}, | ||
"lt" -> forAll { (x: A, y: A) => | ||
A.lt(x, y) ?== (A.lteqv(x, y) && A.neqv(x, y)) | ||
}, | ||
"gt" -> forAll { (x: A, y: A) => | ||
A.lt(x, y) ?== A.gt(y, x) | ||
} | ||
) | ||
|
||
def order(implicit A: Order[A]) = new OrderProperties( | ||
name = "order", | ||
parent = Some(partialOrder), | ||
"totality" -> forAll { (x: A, y: A) => | ||
A.lteqv(x, y) ?|| A.lteqv(y, x) | ||
} | ||
) | ||
|
||
class OrderProperties( | ||
name: String, | ||
parent: Option[RuleSet], | ||
props: (String, Prop)* | ||
) extends DefaultRuleSet(name, parent, props: _*) | ||
|
||
} |
Oops, something went wrong.
Should this be called the substitution property rather than antisymmetry? Citing from the Wikipedia page on Equality:
/cc @non @johnynek @rklaehn