Laws for testing type class instances in the Cats functional programming library for Scala
npx @tessl/cli install tessl/maven-org-typelevel--cats-laws_native0-5_2-13@2.12.0A comprehensive library providing laws for testing type class instances in the Cats functional programming library for Scala. The cats-laws package ensures that type class implementations satisfy the mathematical laws they should uphold, providing property-based testing capabilities for functional programming abstractions.
libraryDependencies += "org.typelevel" %% "cats-laws" % "2.13.0"import cats.laws._
import cats.laws.discipline._For ScalaCheck testing:
import cats.laws.discipline.FunctorTests
import org.scalacheck.Prop._import cats.laws.discipline.MonadTests
import cats.syntax.all._
import org.scalacheck.{Arbitrary, Gen}
import org.scalatest.funsuite.AnyFunSuite
import org.scalatestplus.scalacheck.Checkers
class OptionLawTests extends AnyFunSuite with Checkers {
// Test that Option satisfies Monad laws
checkAll("Option.MonadLaws", MonadTests[Option].monad[Int, Int, String])
// Test that List satisfies Functor laws
checkAll("List.FunctorLaws", FunctorTests[List].functor[Int, Int, String])
}The cats-laws library is organized into two main packages:
cats.laws - Contains trait definitions for mathematical laws that type classes must satisfycats.laws.discipline - Contains ScalaCheck-based test implementations for property-based testingEach type class in Cats has corresponding Laws and Tests classes following a consistent pattern:
*Laws[F[_]] traits define the mathematical properties as methods returning IsEq[T]*Tests[F[_]] traits provide ScalaCheck property tests via RuleSet objectsapply methods for instantiationThe foundational laws for basic type class hierarchies including Functor, Applicative, and Monad.
trait FunctorLaws[F[_]] extends InvariantLaws[F] {
implicit def F: Functor[F]
def covariantIdentity[A](fa: F[A]): IsEq[F[A]]
def covariantComposition[A, B, C](fa: F[A], f: A => B, g: B => C): IsEq[F[C]]
}
trait MonadLaws[F[_]] extends ApplicativeLaws[F] with FlatMapLaws[F] {
def monadLeftIdentity[A, B](a: A, f: A => F[B]): IsEq[F[B]]
def monadRightIdentity[A](fa: F[A]): IsEq[F[A]]
}Laws for alternative operations and monoid structures on type constructors.
trait AlternativeLaws[F[_]] extends NonEmptyAlternativeLaws[F] with MonoidKLaws[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]]
}
trait MonoidKLaws[F[_]] extends SemigroupKLaws[F] {
implicit def F: MonoidK[F]
}Laws for traverse and foldable operations that work with applicative effects.
trait TraverseLaws[F[_]] extends FunctorLaws[F] with FoldableLaws[F] {
implicit override def F: Traverse[F]
}
trait FoldableLaws[F[_]] {
implicit def F: Foldable[F]
}Laws for bifunctors and related binary type constructors.
trait BifunctorLaws[F[_, _]] {
implicit def F: Bifunctor[F]
def bifunctorIdentity[A, B](fab: F[A, B]): IsEq[F[A, B]]
def bifunctorComposition[A, B, C, D](fab: F[A, B], f: A => C, g: B => D, f2: C => C, g2: D => D): IsEq[F[C, D]]
}Laws for comonads and coflatMap operations.
trait ComonadLaws[F[_]] extends CoflatMapLaws[F] {
implicit override def F: Comonad[F]
}
trait CoflatMapLaws[F[_]] extends FunctorLaws[F] {
implicit override def F: CoflatMap[F]
}Laws for categories, arrows, and compositional structures.
trait CategoryLaws[F[_, _]] extends ComposeLaws[F] {
implicit override def F: Category[F]
}
trait ArrowLaws[F[_, _]] extends CategoryLaws[F] with StrongLaws[F] {
implicit override def F: Arrow[F]
}Laws for commutative versions of applicative functors and monads.
trait CommutativeMonadLaws[F[_]] extends CommutativeApplicativeLaws[F] with CommutativeFlatMapLaws[F] with MonadLaws[F]
trait CommutativeApplicativeLaws[F[_]] extends CommutativeApplyLaws[F] with ApplicativeLaws[F]Laws for error handling with ApplicativeError and MonadError.
trait ApplicativeErrorLaws[F[_], E] extends ApplicativeLaws[F] {
implicit override def F: ApplicativeError[F, E]
}
trait MonadErrorLaws[F[_], E] extends ApplicativeErrorLaws[F, E] with MonadLaws[F] {
implicit override def F: MonadError[F, E]
}Laws for parallel operations and alignment of functors.
trait ParallelLaws[M[_], F[_]] {
def parallel: Parallel.Aux[M, F]
}
trait AlignLaws[F[_]] extends FunctorLaws[F] {
implicit override def F: Align[F]
def alignAssociativity[A, B, C](fa: F[A], fb: F[B], fc: F[C]): IsEq[F[Ior[Ior[A, B], C]]]
}Utility classes and objects for property-based testing and law verification.
trait ExhaustiveCheck[A] {
def allValues: List[A]
}
case class MiniInt(toInt: Int) extends AnyVal {
def +(other: MiniInt): MiniInt
def *(other: MiniInt): MiniInt
}// Core law verification type
type IsEq[A] = cats.kernel.laws.IsEq[A]
// Implicit class for creating IsEq instances
implicit final class IsEqArrow[A](private val lhs: A) extends AnyVal {
def <->(rhs: A): IsEq[A]
}
// ScalaCheck rule sets for organized testing
trait RuleSet {
def name: String
def bases: Seq[(String, RuleSet)]
def props: Seq[(String, Prop)]
}