CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-typelevel--cats-laws-native0-5-2-13

Laws for testing type class instances in the Cats functional programming library for Scala

Overview
Eval results
Files

error-laws.mddocs/

Error Handling Laws

Laws for error handling with ApplicativeError and MonadError, providing principled error recovery and handling.

Imports

import cats.laws._
import cats.laws.discipline._
import cats.ApplicativeError
import cats.MonadError

ApplicativeError Laws

Laws for applicative functors that can handle and recover from errors.

trait ApplicativeErrorLaws[F[_], E] extends ApplicativeLaws[F] {
  implicit override def F: ApplicativeError[F, E]
  
  def applicativeErrorHandleWith[A](e: E, f: E => F[A]): IsEq[F[A]]
  def applicativeErrorHandle[A](e: E, f: E => A): IsEq[F[A]]
  def handleErrorWithPure[A](a: A, f: E => F[A]): IsEq[F[A]]
  def handleErrorPure[A](a: A, f: E => A): IsEq[F[A]]
  def raiseErrorAttempt(e: E): IsEq[F[Either[E, Unit]]]
  def pureAttempt[A](a: A): IsEq[F[Either[E, A]]]
  def handleErrorWithConsistentWithRecoverWith[A](fa: F[A], f: E => F[A]): IsEq[F[A]]
  def handleErrorConsistentWithRecover[A](fa: F[A], f: E => A): IsEq[F[A]]
  def recoverConsistentWithRecoverWith[A](fa: F[A], pf: PartialFunction[E, A]): IsEq[F[A]]
  def attemptConsistentWithAttemptT[A](fa: F[A]): IsEq[EitherT[F, E, A]]
  def attemptFromEitherConsistentWithPure[A](eab: Either[E, A]): IsEq[F[Either[E, A]]]
  def voidErrorConsistentWithHandleError(fu: F[Unit]): IsEq[F[Unit]]
  def onErrorPure[A](a: A, f: E => F[Unit]): IsEq[F[A]]
  def onErrorRaise[A](fa: F[A], e: E, fb: F[Unit]): IsEq[F[A]]
  def adaptErrorPure[A](a: A, f: E => E): IsEq[F[A]]
  def adaptErrorRaise[A](e: E, f: E => E): IsEq[F[A]]
  def redeemDerivedFromAttemptMap[A, B](fa: F[A], fe: E => B, fs: A => B): IsEq[F[B]]
  def raiseErrorDistributesOverApLeft[A](h: E => F[A], e: E): IsEq[F[A]]
  def raiseErrorDistributesOverApRight[A](h: E => F[A], e: E): IsEq[F[A]]
}

object ApplicativeErrorLaws {
  def apply[F[_], E](implicit ev: ApplicativeError[F, E]): ApplicativeErrorLaws[F, E]
}

ApplicativeErrorTests

trait ApplicativeErrorTests[F[_], E] extends ApplicativeTests[F] {
  def laws: ApplicativeErrorLaws[F, E]
  
  def applicativeError[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]],
    ArbE: Arbitrary[E],
    CogenA: Cogen[A],
    CogenB: Cogen[B],
    CogenC: Cogen[C],
    CogenE: Cogen[E],
    EqFA: Eq[F[A]],
    EqFB: Eq[F[B]],
    EqFC: Eq[F[C]],
    EqE: Eq[E],
    EqFEitherEA: Eq[F[Either[E, A]]],
    EqFEitherEB: Eq[F[Either[E, B]]],
    EqFEitherEC: Eq[F[Either[E, C]]],
    EqFUnit: Eq[F[Unit]],
    iso: Isomorphisms[F]
  ): RuleSet
}

object ApplicativeErrorTests {
  def apply[F[_], E](implicit ev: ApplicativeError[F, E]): ApplicativeErrorTests[F, E]
}

MonadError Laws

Laws for monads that can handle errors, extending both ApplicativeError and Monad.

trait MonadErrorLaws[F[_], E] extends ApplicativeErrorLaws[F, E] with MonadLaws[F] {
  implicit override def F: MonadError[F, E]
  
  def monadErrorLeftZero[A, B](e: E, f: A => F[B]): IsEq[F[B]]
  def monadErrorEnsureConsistency[A](fa: F[A], e: E, p: A => Boolean): IsEq[F[A]]
  def monadErrorEnsureOrConsistency[A](fa: F[A], e: A => E, p: A => Boolean): IsEq[F[A]]
  def adaptErrorPure[A](a: A, f: E => E): IsEq[F[A]]
  def adaptErrorRaise[A](e: E, f: E => E): IsEq[F[A]]
  def rethrowAttempt[A](fa: F[A]): IsEq[F[A]]
  def redeemWithDerivedFromAttemptFlatMap[A, B](fa: F[A], fe: E => F[B], fs: A => F[B]): IsEq[F[B]]
}

object MonadErrorLaws {
  def apply[F[_], E](implicit ev: MonadError[F, E]): MonadErrorLaws[F, E]
}

MonadErrorTests

trait MonadErrorTests[F[_], E] extends ApplicativeErrorTests[F, E] with MonadTests[F] {
  def laws: MonadErrorLaws[F, E]
  
  def monadError[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]],
    ArbE: Arbitrary[E],
    CogenA: Cogen[A],
    CogenB: Cogen[B],
    CogenC: Cogen[C],
    CogenE: Cogen[E],
    EqFA: Eq[F[A]],
    EqFB: Eq[F[B]],
    EqFC: Eq[F[C]],
    EqE: Eq[E],
    EqFEitherEA: Eq[F[Either[E, A]]],
    EqFEitherEB: Eq[F[Either[E, B]]],
    EqFEitherEC: Eq[F[Either[E, C]]],
    EqFUnit: Eq[F[Unit]],
    EqFInt: Eq[F[Int]],
    iso: Isomorphisms[F]
  ): RuleSet
}

object MonadErrorTests {
  def apply[F[_], E](implicit ev: MonadError[F, E]): MonadErrorTests[F, E]
}

Usage Examples

Testing Either as MonadError

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

class EitherMonadErrorTest extends AnyFunSuite with Checkers {
  checkAll("Either.MonadErrorLaws", MonadErrorTests[Either[String, *], String].monadError[Int, String, Double])
}

Testing Try as ApplicativeError

import cats.laws.discipline.ApplicativeErrorTests
import scala.util.Try

class TryApplicativeErrorTest extends AnyFunSuite with Checkers {
  checkAll("Try.ApplicativeErrorLaws", ApplicativeErrorTests[Try, Throwable].applicativeError[Int, String, Double])
}

Custom Error Law Verification

import cats.laws.MonadErrorLaws
import cats.syntax.all._

val laws = MonadErrorLaws[Either[String, *], String]

// Verify error handling
val handleLaw = laws.applicativeErrorHandle("error", (e: String) => e.length)
assert(handleLaw.lhs == handleLaw.rhs)

// Verify left zero law (error short-circuits)
val leftZeroLaw = laws.monadErrorLeftZero[Int, String](
  "error", 
  (x: Int) => Right(x.toString)
)
assert(leftZeroLaw.lhs == leftZeroLaw.rhs)

Install with Tessl CLI

npx tessl i tessl/maven-org-typelevel--cats-laws-native0-5-2-13

docs

alternative-laws.md

bifunctor-laws.md

category-laws.md

commutative-laws.md

comonad-laws.md

core-laws.md

error-laws.md

index.md

parallel-laws.md

testing-utilities.md

traversal-laws.md

tile.json