or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

alternative-laws.mdbifunctor-laws.mdcategory-laws.mdcommutative-laws.mdcomonad-laws.mdcore-laws.mderror-laws.mdindex.mdparallel-laws.mdtesting-utilities.mdtraversal-laws.md
tile.json

alternative-laws.mddocs/

Alternative and MonoidK Laws

Laws for alternative operations and monoid structures on type constructors, providing choice operations and empty values.

Imports

import cats.laws._
import cats.laws.discipline._
import cats.Alternative
import cats.MonoidK
import cats.SemigroupK

SemigroupK Laws

Laws 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]
}

SemigroupKTests

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]
}

MonoidK Laws

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]
}

MonoidKTests

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]
}

NonEmptyAlternative Laws

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]
}

NonEmptyAlternativeTests

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]
}

Alternative Laws

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]
}

AlternativeTests

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]
}

Usage Examples

Testing List as Alternative

import cats.laws.discipline.AlternativeTests
import cats.syntax.all._

class ListAlternativeTest extends AnyFunSuite with Checkers {
  checkAll("List.AlternativeLaws", AlternativeTests[List].alternative[Int, String, Double])
}

Testing Option as MonoidK

import cats.laws.discipline.MonoidKTests

class OptionMonoidKTest extends AnyFunSuite with Checkers {
  checkAll("Option.MonoidKLaws", MonoidKTests[Option].monoidK[Int])
}

Custom Alternative Law Verification

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)