Laws for testing type class instances in the Cats functional programming library for Scala
Laws for alternative operations and monoid structures on type constructors, providing choice operations and empty values.
import cats.laws._
import cats.laws.discipline._
import cats.Alternative
import cats.MonoidK
import cats.SemigroupKLaws for semigroup operations on type constructors.
trait SemigroupKLaws[F[_]] {
implicit def F: SemigroupK[F]
def semigroupKAssociativity[A](a: F[A], b: F[A], c: F[A]): IsEq[F[A]]
}
object SemigroupKLaws {
def apply[F[_]](implicit ev: SemigroupK[F]): SemigroupKLaws[F]
}trait SemigroupKTests[F[_]] {
def laws: SemigroupKLaws[F]
def semigroupK[A: Arbitrary](implicit
ArbFA: Arbitrary[F[A]],
EqFA: Eq[F[A]]
): RuleSet
}
object SemigroupKTests {
def apply[F[_]: SemigroupK]: SemigroupKTests[F]
}Laws for monoid operations on type constructors, extending SemigroupK with an identity element.
trait MonoidKLaws[F[_]] extends SemigroupKLaws[F] {
implicit override def F: MonoidK[F]
def monoidKLeftIdentity[A](a: F[A]): IsEq[F[A]]
def monoidKRightIdentity[A](a: F[A]): IsEq[F[A]]
}
object MonoidKLaws {
def apply[F[_]](implicit ev: MonoidK[F]): MonoidKLaws[F]
}trait MonoidKTests[F[_]] extends SemigroupKTests[F] {
def laws: MonoidKLaws[F]
def monoidK[A: Arbitrary](implicit
ArbFA: Arbitrary[F[A]],
EqFA: Eq[F[A]]
): RuleSet
}
object MonoidKTests {
def apply[F[_]: MonoidK]: MonoidKTests[F]
}Laws for non-empty alternative operations.
trait NonEmptyAlternativeLaws[F[_]] extends ApplicativeLaws[F] with SemigroupKLaws[F] {
implicit override def F: NonEmptyAlternative[F]
def nonEmptyAlternativeLeftDistributivity[A, B](fa: F[A], fa2: F[A], f: A => B): IsEq[F[B]]
def nonEmptyAlternativeRightDistributivity[A, B](fa: F[A], ff: F[A => B], ff2: F[A => B]): IsEq[F[B]]
}
object NonEmptyAlternativeLaws {
def apply[F[_]](implicit ev: NonEmptyAlternative[F]): NonEmptyAlternativeLaws[F]
}trait NonEmptyAlternativeTests[F[_]] extends ApplicativeTests[F] with SemigroupKTests[F] {
def laws: NonEmptyAlternativeLaws[F]
def nonEmptyAlternative[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit
ArbFA: Arbitrary[F[A]],
ArbFB: Arbitrary[F[B]],
ArbFC: Arbitrary[F[C]],
ArbFAtoB: Arbitrary[F[A => B]],
ArbFBtoC: Arbitrary[F[B => C]],
CogenA: Cogen[A],
CogenB: Cogen[B],
CogenC: Cogen[C],
EqFA: Eq[F[A]],
EqFB: Eq[F[B]],
EqFC: Eq[F[C]],
EqFABC: Eq[F[((A, B), C)]],
iso: Isomorphisms[F]
): RuleSet
}
object NonEmptyAlternativeTests {
def apply[F[_]: NonEmptyAlternative]: NonEmptyAlternativeTests[F]
}Laws for alternative operations, combining applicative and monoid-like choice operations.
trait AlternativeLaws[F[_]] extends NonEmptyAlternativeLaws[F] with MonoidKLaws[F] {
implicit override def F: Alternative[F]
def alternativeRightAbsorption[A, B](ff: F[A => B]): IsEq[F[B]]
def alternativeLeftDistributivity[A](fa: F[A], fa2: F[A], f: A => A): IsEq[F[A]]
def alternativeRightDistributivity[A](fa: F[A], ff: F[A => A], ff2: F[A => A]): IsEq[F[A]]
def fromIterableOnce[A](it: List[A]): IsEq[F[A]]
}
object AlternativeLaws {
def apply[F[_]](implicit ev: Alternative[F]): AlternativeLaws[F]
}trait AlternativeTests[F[_]] extends NonEmptyAlternativeTests[F] with MonoidKTests[F] {
def laws: AlternativeLaws[F]
def alternative[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit
ArbFA: Arbitrary[F[A]],
ArbFB: Arbitrary[F[B]],
ArbFC: Arbitrary[F[C]],
ArbFAtoB: Arbitrary[F[A => B]],
ArbFBtoC: Arbitrary[F[B => C]],
CogenA: Cogen[A],
CogenB: Cogen[B],
CogenC: Cogen[C],
EqFA: Eq[F[A]],
EqFB: Eq[F[B]],
EqFC: Eq[F[C]],
EqFABC: Eq[F[((A, B), C)]],
iso: Isomorphisms[F]
): RuleSet
}
object AlternativeTests {
def apply[F[_]: Alternative]: AlternativeTests[F]
}import cats.laws.discipline.AlternativeTests
import cats.syntax.all._
class ListAlternativeTest extends AnyFunSuite with Checkers {
checkAll("List.AlternativeLaws", AlternativeTests[List].alternative[Int, String, Double])
}import cats.laws.discipline.MonoidKTests
class OptionMonoidKTest extends AnyFunSuite with Checkers {
checkAll("Option.MonoidKLaws", MonoidKTests[Option].monoidK[Int])
}import cats.laws.AlternativeLaws
import cats.syntax.all._
val laws = AlternativeLaws[List]
// Verify left distributivity
val leftDistLaw = laws.alternativeLeftDistributivity(
List(1, 2),
List(3, 4),
(x: Int) => x * 2
)
assert(leftDistLaw.lhs == leftDistLaw.rhs)
// Verify right absorption (empty should absorb)
val rightAbsLaw = laws.alternativeRightAbsorption[Int, String](List.empty)
assert(rightAbsLaw.lhs == rightAbsLaw.rhs)Install with Tessl CLI
npx tessl i tessl/maven-org-typelevel--cats-laws-native0-5-2-13