Laws for comonads and coflatMap operations, dual to monads with extraction instead of injection.
import cats.laws._
import cats.laws.discipline._
import cats.Comonad
import cats.CoflatMaptrait CoflatMapLaws[F[_]] extends FunctorLaws[F] {
implicit override def F: CoflatMap[F]
def coflatMapAssociativity[A, B, C](fa: F[A], f: F[A] => B, g: F[B] => C): IsEq[F[C]]
def coflattenThroughMap[A](fa: F[A]): IsEq[F[F[F[A]]]]
def coflattenCoherence[A, B](fa: F[A], f: F[A] => B): IsEq[F[B]]
def coflatMapIdentity[A, B](fa: F[A], f: A => B): IsEq[F[B]]
def mproductConsistency[A, B](fa: F[A], f: F[A] => B): IsEq[F[(A, B)]]
}
object CoflatMapLaws {
def apply[F[_]](implicit ev: CoflatMap[F]): CoflatMapLaws[F]
}trait CoflatMapTests[F[_]] extends FunctorTests[F] {
def laws: CoflatMapLaws[F]
def coflatMap[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit
ArbFA: Arbitrary[F[A]],
CogenA: Cogen[A],
CogenB: Cogen[B],
CogenC: Cogen[C],
CogenFA: Cogen[F[A]],
CogenFB: Cogen[F[B]],
EqFA: Eq[F[A]],
EqFB: Eq[F[B]],
EqFC: Eq[F[C]],
EqFFFA: Eq[F[F[F[A]]]],
EqFAB: Eq[F[(A, B)]]
): RuleSet
}
object CoflatMapTests {
def apply[F[_]: CoflatMap]: CoflatMapTests[F]
}trait ComonadLaws[F[_]] extends CoflatMapLaws[F] {
implicit override def F: Comonad[F]
def extractCoflattenIdentity[A](fa: F[A]): IsEq[F[A]]
def mapCoflattenIdentity[A](fa: F[A]): IsEq[F[A]]
def comonadLeftIdentity[A](fa: F[A]): IsEq[F[A]]
def comonadRightIdentity[A, B](fa: F[A], f: F[A] => B): IsEq[B]
}
object ComonadLaws {
def apply[F[_]](implicit ev: Comonad[F]): ComonadLaws[F]
}trait ComonadTests[F[_]] extends CoflatMapTests[F] {
def laws: ComonadLaws[F]
def comonad[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit
ArbFA: Arbitrary[F[A]],
CogenA: Cogen[A],
CogenB: Cogen[B],
CogenC: Cogen[C],
CogenFA: Cogen[F[A]],
CogenFB: Cogen[F[B]],
EqA: Eq[A],
EqB: Eq[B],
EqFA: Eq[F[A]],
EqFB: Eq[F[B]],
EqFC: Eq[F[C]],
EqFFFA: Eq[F[F[F[A]]]],
EqFAB: Eq[F[(A, B)]]
): RuleSet
}
object ComonadTests {
def apply[F[_]: Comonad]: ComonadTests[F]
}import cats.laws.discipline.ComonadTests
import cats.data.NonEmptyList
class NonEmptyListComonadTest extends AnyFunSuite with Checkers {
checkAll("NonEmptyList.ComonadLaws", ComonadTests[NonEmptyList].comonad[Int, String, Double])
}