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)