Laws for testing type class instances in the Cats functional programming library for Scala
Laws for bifunctors and related binary type constructors that can map over both type parameters.
import cats.laws._
import cats.laws.discipline._
import cats.Bifunctor
import cats.Bifoldable
import cats.BitraverseLaws for functors with two type parameters.
trait BifunctorLaws[F[_, _]] {
implicit def F: Bifunctor[F]
def bifunctorIdentity[A, B](fa: F[A, B]): IsEq[F[A, B]]
def bifunctorComposition[A, B, C, X, Y, Z](fa: F[A, X], f: A => B, f2: B => C, g: X => Y, g2: Y => Z): IsEq[F[C, Z]]
def bifunctorLeftMapIdentity[A, B](fa: F[A, B]): IsEq[F[A, B]]
def bifunctorLeftMapComposition[A, B, C, D](fa: F[A, B], f: A => C, g: C => D): IsEq[F[D, B]]
}
object BifunctorLaws {
def apply[F[_, _]](implicit ev: Bifunctor[F]): BifunctorLaws[F]
}trait BifunctorTests[F[_, _]] {
def laws: BifunctorLaws[F]
def bifunctor[A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary, E: Arbitrary, G: Arbitrary](implicit
ArbFAB: Arbitrary[F[A, B]],
CogenA: Cogen[A],
CogenB: Cogen[B],
CogenC: Cogen[C],
CogenD: Cogen[D],
EqFAB: Eq[F[A, B]],
EqFCD: Eq[F[C, D]],
EqFEG: Eq[F[E, G]]
): RuleSet
}
object BifunctorTests {
def apply[F[_, _]: Bifunctor]: BifunctorTests[F]
}Laws for structures that can be folded over both type parameters.
trait BifoldableLaws[F[_, _]] {
implicit def F: Bifoldable[F]
def bifoldLeftConsistentWithBifoldMap[A, B, C](
fab: F[A, B],
f: A => C,
g: B => C
)(implicit C: Monoid[C]): IsEq[C]
def bifoldRightConsistentWithBifoldMap[A, B, C](
fab: F[A, B],
f: A => C,
g: B => C,
initial: C
)(implicit C: Monoid[C]): IsEq[C]
def bifoldLeftConsistentWithBifoldMap[A, B, C](
fab: F[A, B],
f: A => C,
g: B => C,
initial: C
)(implicit C: Monoid[C]): IsEq[C]
}
object BifoldableLaws {
def apply[F[_, _]](implicit ev: Bifoldable[F]): BifoldableLaws[F]
}trait BifoldableTests[F[_, _]] {
def laws: BifoldableLaws[F]
def bifoldable[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit
ArbFAB: Arbitrary[F[A, B]],
A: Monoid[A],
B: Monoid[B],
C: Monoid[C],
CogenA: Cogen[A],
CogenB: Cogen[B],
EqA: Eq[A],
EqB: Eq[B],
EqC: Eq[C]
): RuleSet
}
object BifoldableTests {
def apply[F[_, _]: Bifoldable]: BifoldableTests[F]
}Laws for structures that can be traversed over both type parameters with applicative effects.
trait BitraverseLaws[F[_, _]] extends BifunctorLaws[F] with BifoldableLaws[F] {
implicit override def F: Bitraverse[F]
def bitraverseIdentity[A, B](fab: F[A, B]): IsEq[F[A, B]]
def bitraverseCompose[G[_], A, B, C, D, E, H](
fab: F[A, B],
f: A => G[C],
g: B => G[D],
h: C => G[E],
i: D => G[H]
)(implicit G: Applicative[G]): IsEq[G[G[F[E, H]]]]
}
object BitraverseLaws {
def apply[F[_, _]](implicit ev: Bitraverse[F]): BitraverseLaws[F]
}trait BitraverseTests[F[_, _]] extends BifunctorTests[F] with BifoldableTests[F] {
def laws: BitraverseLaws[F]
def bitraverse[A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary, E: Arbitrary, G: Arbitrary, M: Applicative, N: Applicative](implicit
ArbFAB: Arbitrary[F[A, B]],
ArbFMAMB: Arbitrary[F[M[A], M[B]]],
CogenA: Cogen[A],
CogenB: Cogen[B],
CogenC: Cogen[C],
CogenD: Cogen[D],
EqFAB: Eq[F[A, B]],
EqFCD: Eq[F[C, D]],
EqFEG: Eq[F[E, G]],
EqMFAB: Eq[M[F[A, B]]],
EqMFCD: Eq[M[F[C, D]]],
EqMFEG: Eq[M[F[E, G]]],
EqMNFEG: Eq[M[N[F[E, G]]]]
): RuleSet
}
object BitraverseTests {
def apply[F[_, _]: Bitraverse]: BitraverseTests[F]
}import cats.laws.discipline.BifunctorTests
import cats.syntax.all._
class EitherBifunctorTest extends AnyFunSuite with Checkers {
checkAll("Either.BifunctorLaws", BifunctorTests[Either].bifunctor[Int, String, Double, Boolean, Long, Char])
}import cats.laws.discipline.BitraverseTests
class Tuple2BitraverseTest extends AnyFunSuite with Checkers {
checkAll("Tuple2.BitraverseLaws", BitraverseTests[Tuple2].bitraverse[Int, String, Double, Boolean, Long, Char, Option, Option])
}import cats.laws.BifunctorLaws
import cats.syntax.all._
val laws = BifunctorLaws[Either]
// Verify bifunctor identity law
val identityLaw = laws.bifunctorIdentity(Right("hello"): Either[Int, String])
assert(identityLaw.lhs == identityLaw.rhs)
// Verify bifunctor composition law
val compositionLaw = laws.bifunctorComposition(
Left(5): Either[Int, String],
(x: Int) => x * 2, (x: Int) => x + 1,
(s: String) => s.length, (i: Int) => i.toString
)
assert(compositionLaw.lhs == compositionLaw.rhs)Install with Tessl CLI
npx tessl i tessl/maven-org-typelevel--cats-laws-native0-5-2-13