├── .gitignore ├── .jvmopts ├── .travis.yml ├── AUTHORS.md ├── CHANGES.md ├── CONTRIBUTING.md ├── COPYING ├── DESIGN.md ├── PROCESS.md ├── README.md ├── bench └── src │ └── main │ └── scala │ └── cats │ └── bench │ ├── FoldBench.scala │ ├── MapMonoidBench.scala │ └── TrampolineBench.scala ├── build.sbt ├── core └── src │ └── main │ └── scala │ └── cats │ ├── Alternative.scala │ ├── Applicative.scala │ ├── ApplicativeError.scala │ ├── Apply.scala │ ├── Bifoldable.scala │ ├── Bimonad.scala │ ├── Bitraverse.scala │ ├── Cartesian.scala │ ├── CoflatMap.scala │ ├── Comonad.scala │ ├── Composed.scala │ ├── ContravariantCartesian.scala │ ├── Eval.scala │ ├── FlatMap.scala │ ├── Foldable.scala │ ├── Functor.scala │ ├── FunctorFilter.scala │ ├── InvariantMonoidal.scala │ ├── Monad.scala │ ├── MonadCombine.scala │ ├── MonadError.scala │ ├── MonadFilter.scala │ ├── MonadReader.scala │ ├── MonadState.scala │ ├── MonadWriter.scala │ ├── MonoidK.scala │ ├── NotNull.scala │ ├── RecursiveTailRecM.scala │ ├── Reducible.scala │ ├── SemigroupK.scala │ ├── Show.scala │ ├── TransLift.scala │ ├── Traverse.scala │ ├── TraverseFilter.scala │ ├── Trivial.scala │ ├── Unapply.scala │ ├── arrow │ ├── Arrow.scala │ ├── Category.scala │ ├── Choice.scala │ ├── Compose.scala │ ├── FunctionK.scala │ └── Split.scala │ ├── data │ ├── Cokleisli.scala │ ├── Const.scala │ ├── Coproduct.scala │ ├── EitherT.scala │ ├── Func.scala │ ├── IdT.scala │ ├── Ior.scala │ ├── Kleisli.scala │ ├── Nested.scala │ ├── NonEmptyList.scala │ ├── NonEmptyVector.scala │ ├── OneAnd.scala │ ├── OptionT.scala │ ├── Prod.scala │ ├── StateT.scala │ ├── Validated.scala │ ├── WriterT.scala │ └── package.scala │ ├── functor │ ├── Bifunctor.scala │ ├── Contravariant.scala │ ├── Invariant.scala │ ├── Profunctor.scala │ └── Strong.scala │ ├── implicits │ └── package.scala │ ├── instances │ ├── all.scala │ ├── anyval.scala │ ├── bigDecimal.scala │ ├── bigInt.scala │ ├── either.scala │ ├── function.scala │ ├── future.scala │ ├── list.scala │ ├── map.scala │ ├── option.scala │ ├── package.scala │ ├── set.scala │ ├── stream.scala │ ├── string.scala │ ├── try.scala │ ├── tuple.scala │ └── vector.scala │ ├── package.scala │ └── syntax │ ├── all.scala │ ├── applicative.scala │ ├── applicativeError.scala │ ├── apply.scala │ ├── bifoldable.scala │ ├── bifunctor.scala │ ├── bitraverse.scala │ ├── cartesian.scala │ ├── coflatMap.scala │ ├── comonad.scala │ ├── compose.scala │ ├── contravariant.scala │ ├── coproduct.scala │ ├── either.scala │ ├── eq.scala │ ├── flatMap.scala │ ├── foldable.scala │ ├── functor.scala │ ├── functorFilter.scala │ ├── group.scala │ ├── invariant.scala │ ├── list.scala │ ├── monadCombine.scala │ ├── monadError.scala │ ├── monadFilter.scala │ ├── monoid.scala │ ├── option.scala │ ├── order.scala │ ├── package.scala │ ├── partialOrder.scala │ ├── profunctor.scala │ ├── reducible.scala │ ├── semigroup.scala │ ├── semigroupk.scala │ ├── split.scala │ ├── strong.scala │ ├── transLift.scala │ ├── traverse.scala │ ├── traverseFilter.scala │ ├── tuple.scala │ ├── validated.scala │ └── writer.scala ├── docs └── src │ ├── main │ └── tut │ │ ├── applicative.md │ │ ├── apply.md │ │ ├── const.md │ │ ├── contravariant.md │ │ ├── either.md │ │ ├── faq.md │ │ ├── foldable.md │ │ ├── freeapplicative.md │ │ ├── freemonad.md │ │ ├── functor.md │ │ ├── id.md │ │ ├── imports.md │ │ ├── invariant.md │ │ ├── invariantmonoidal.md │ │ ├── kleisli.md │ │ ├── monad.md │ │ ├── monadcombine.md │ │ ├── monadfilter.md │ │ ├── monoid.md │ │ ├── monoidk.md │ │ ├── oneand.md │ │ ├── optiont.md │ │ ├── semigroup.md │ │ ├── semigroupk.md │ │ ├── show.md │ │ ├── state.md │ │ ├── symbols.md │ │ ├── traverse.md │ │ ├── typeclasses.md │ │ └── validated.md │ └── site │ ├── _config.yml │ ├── _layouts │ └── default.html │ ├── bin │ └── local-server │ ├── colophon.md │ ├── css │ ├── custom.css │ ├── styles.css │ └── syntax.css │ ├── datatypes.md │ ├── index.md │ ├── js │ └── scale.fix.js │ ├── resources_for_learners.md │ └── typeclasses.md ├── free └── src │ ├── main │ └── scala │ │ └── cats │ │ └── free │ │ ├── Coyoneda.scala │ │ ├── Free.scala │ │ ├── FreeApplicative.scala │ │ ├── FreeInvariantMonoidal.scala │ │ ├── FreeT.scala │ │ ├── Inject.scala │ │ ├── Trampoline.scala │ │ ├── Yoneda.scala │ │ └── package.scala │ └── test │ └── scala │ └── cats │ └── free │ ├── CoyonedaTests.scala │ ├── FreeApplicativeTests.scala │ ├── FreeInvariantMonoidalTests.scala │ ├── FreeTTests.scala │ ├── FreeTests.scala │ ├── InjectTests.scala │ └── YonedaTests.scala ├── js └── src │ ├── main │ └── scala │ │ └── cats │ │ └── js │ │ └── std │ │ └── future.scala │ └── test │ └── scala │ └── cats │ └── tests │ └── FutureTests.scala ├── jvm └── src │ └── test │ └── scala │ └── cats │ └── tests │ └── FutureTests.scala ├── kernel-laws └── src │ ├── main │ └── scala │ │ └── cats │ │ └── kernel │ │ └── laws │ │ ├── BaseLaws.scala │ │ ├── GroupLaws.scala │ │ ├── IsSerializable.scala │ │ ├── OrderLaws.scala │ │ ├── Rules.scala │ │ └── package.scala │ └── test │ └── scala │ └── cats │ └── kernel │ └── laws │ └── LawTests.scala ├── kernel └── src │ └── main │ └── scala │ └── cats │ └── kernel │ ├── Band.scala │ ├── BoundedSemilattice.scala │ ├── CommutativeGroup.scala │ ├── CommutativeMonoid.scala │ ├── CommutativeSemigroup.scala │ ├── Comparison.scala │ ├── Eq.scala │ ├── Group.scala │ ├── Monoid.scala │ ├── Order.scala │ ├── PartialOrder.scala │ ├── Semigroup.scala │ ├── Semilattice.scala │ └── instances │ ├── StaticMethods.scala │ ├── all.scala │ ├── bigDecimal.scala │ ├── bigInt.scala │ ├── bitSet.scala │ ├── boolean.scala │ ├── byte.scala │ ├── char.scala │ ├── double.scala │ ├── either.scala │ ├── float.scala │ ├── function.scala │ ├── int.scala │ ├── list.scala │ ├── long.scala │ ├── map.scala │ ├── option.scala │ ├── set.scala │ ├── short.scala │ ├── stream.scala │ ├── string.scala │ ├── tuple.scala │ ├── unit.scala │ └── vector.scala ├── laws └── src │ └── main │ └── scala │ └── cats │ └── laws │ ├── AlternativeLaws.scala │ ├── ApplicativeErrorLaws.scala │ ├── ApplicativeLaws.scala │ ├── ApplyLaws.scala │ ├── ArrowLaws.scala │ ├── BifoldableLaws.scala │ ├── BifunctorLaws.scala │ ├── BimonadLaws.scala │ ├── BitraverseLaws.scala │ ├── CartesianLaws.scala │ ├── CategoryLaws.scala │ ├── ChoiceLaws.scala │ ├── CoflatMapLaws.scala │ ├── ComonadLaws.scala │ ├── ComposeLaws.scala │ ├── ContravariantLaws.scala │ ├── FlatMapLaws.scala │ ├── FoldableLaws.scala │ ├── FunctorFilterLaws.scala │ ├── FunctorLaws.scala │ ├── InvariantLaws.scala │ ├── InvariantMonoidalLaws.scala │ ├── IsEq.scala │ ├── MonadCombineLaws.scala │ ├── MonadErrorLaws.scala │ ├── MonadFilterLaws.scala │ ├── MonadLaws.scala │ ├── MonadReaderLaws.scala │ ├── MonadStateLaws.scala │ ├── MonadWriterLaws.scala │ ├── MonoidKLaws.scala │ ├── ProfunctorLaws.scala │ ├── ReducibleLaws.scala │ ├── SemigroupKLaws.scala │ ├── SerializableLaws.scala │ ├── SplitLaws.scala │ ├── StrongLaws.scala │ ├── TraverseFilterLaws.scala │ ├── TraverseLaws.scala │ ├── discipline │ ├── AlternativeTests.scala │ ├── ApplicativeErrorTests.scala │ ├── ApplicativeTests.scala │ ├── ApplyTests.scala │ ├── Arbitrary.scala │ ├── ArrowTests.scala │ ├── BifoldableTests.scala │ ├── BifunctorTests.scala │ ├── BimonadTests.scala │ ├── BitraverseTests.scala │ ├── CartesianTests.scala │ ├── CategoryTests.scala │ ├── ChoiceTests.scala │ ├── CoflatMapTests.scala │ ├── ComonadTests.scala │ ├── ComposeTests.scala │ ├── ContravariantTests.scala │ ├── Eq.scala │ ├── FlatMapTests.scala │ ├── FoldableTests.scala │ ├── FunctorFilterTests.scala │ ├── FunctorTests.scala │ ├── InvariantMonoidalTests.scala │ ├── InvariantTests.scala │ ├── MonadCombineTests.scala │ ├── MonadErrorTests.scala │ ├── MonadFilterTests.scala │ ├── MonadReaderTests.scala │ ├── MonadStateTests.scala │ ├── MonadTests.scala │ ├── MonadWriterTests.scala │ ├── MonoidKTests.scala │ ├── ProfunctorTests.scala │ ├── ReducibleTests.scala │ ├── SemigroupKTests.scala │ ├── SerializableTests.scala │ ├── SplitTests.scala │ ├── StrongTests.scala │ ├── TraverseFilterTests.scala │ ├── TraverseTests.scala │ └── package.scala │ └── package.scala ├── macros └── src │ └── main │ └── scala │ └── cats │ └── macros │ └── Ops.scala ├── project ├── Boilerplate.scala ├── KernelBoiler.scala ├── build.properties └── plugins.sbt ├── scalastyle-config.xml ├── scripts ├── sbtrc-JVM └── travis-publish.sh ├── tests └── src │ └── test │ └── scala │ └── cats │ └── tests │ ├── AlgebraInvariantTests.scala │ ├── ApplicativeErrorTests.scala │ ├── ApplicativeTests.scala │ ├── BifoldableTests.scala │ ├── BifunctorTests.scala │ ├── BitraverseTests.scala │ ├── CategoryTests.scala │ ├── CatsEquality.scala │ ├── CatsSuite.scala │ ├── CokleisliTests.scala │ ├── ComposeTest.scala │ ├── ConstTests.scala │ ├── ContravariantTests.scala │ ├── CoproductTests.scala │ ├── CsvCodecInvariantMonoidalTests.scala │ ├── EitherTTests.scala │ ├── EitherTests.scala │ ├── EvalTests.scala │ ├── FoldableTests.scala │ ├── FuncTests.scala │ ├── FunctionKTests.scala │ ├── FunctionTests.scala │ ├── FunctorTests.scala │ ├── Helpers.scala │ ├── IdTTests.scala │ ├── IdTests.scala │ ├── IorTests.scala │ ├── KernelContravariantTests.scala │ ├── KleisliTests.scala │ ├── ListTests.scala │ ├── ListWrapper.scala │ ├── MapTests.scala │ ├── MonadCombineTests.scala │ ├── MonadErrorSuite.scala │ ├── MonadRecInstancesTests.scala │ ├── MonadStateTests.scala │ ├── NestedTests.scala │ ├── NonEmptyListTests.scala │ ├── NonEmptyVectorTests.scala │ ├── OneAndTests.scala │ ├── OptionTTests.scala │ ├── OptionTests.scala │ ├── ProdTests.scala │ ├── ReducibleTests.scala │ ├── RegressionTests.scala │ ├── SetTests.scala │ ├── ShowTests.scala │ ├── StateTTests.scala │ ├── StreamTests.scala │ ├── SyntaxTests.scala │ ├── TransLiftTests.scala │ ├── TryTests.scala │ ├── TupleTests.scala │ ├── UnapplyTests.scala │ ├── ValidatedTests.scala │ ├── VectorTests.scala │ ├── WordCountTest.scala │ ├── WriterTTests.scala │ └── WriterTests.scala └── version.sbt /.gitignore: -------------------------------------------------------------------------------- 1 | project/boot 2 | target 3 | .ensime 4 | .ensime_lucene 5 | .ensime_cache 6 | TAGS 7 | \#*# 8 | *~ 9 | .#* 10 | .lib 11 | .history 12 | .*.swp 13 | .idea 14 | .idea/* 15 | .idea_modules 16 | .DS_Store 17 | .sbtrc 18 | *.sublime-project 19 | *.sublime-workspace 20 | tests.iml 21 | -------------------------------------------------------------------------------- /.jvmopts: -------------------------------------------------------------------------------- 1 | # see https://weblogs.java.net/blog/kcpeppe/archive/2013/12/11/case-study-jvm-hotspot-flags 2 | -Dfile.encoding=UTF8 3 | -Xms1G 4 | -Xmx3G 5 | -XX:MaxPermSize=512M 6 | -XX:ReservedCodeCacheSize=250M 7 | -XX:+TieredCompilation 8 | -XX:-UseGCOverheadLimit 9 | # effectively adds GC to Perm space 10 | -XX:+CMSClassUnloadingEnabled 11 | # must be enabled for CMSClassUnloadingEnabled to work 12 | -XX:+UseConcMarkSweepGC 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: scala 2 | 3 | git: 4 | depth: 9999 5 | 6 | scala: 7 | - 2.10.6 8 | - 2.11.8 9 | 10 | script: 11 | - scripts/travis-publish.sh 12 | 13 | # http://austinpray.com/ops/2015/09/20/change-travis-node-version.html 14 | install: 15 | - rm -rf ~/.nvm && git clone https://github.com/creationix/nvm.git ~/.nvm && (cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`) && source ~/.nvm/nvm.sh && nvm install $TRAVIS_NODE_VERSION 16 | - pip install --user codecov 17 | 18 | notifications: 19 | webhooks: 20 | urls: 21 | - https://webhooks.gitter.im/e/2d5ea16a2f66f60a590b 22 | on_success: change 23 | on_failure: always 24 | on_start: false 25 | env: 26 | global: 27 | - secure: Kf44XQFpq2QGe3rn98Dsf5Uz3WXzPDralS54co7sqT5oQGs1mYLYZRYz+I75ZSo5ffZ86H7M+AI9YFofqGwAjBixBbqf1tGkUh3oZp2fN3QfqzazGV3HzC+o41zALG5FL+UBaURev9ChQ5fYeTtFB7YAzejHz4y5E97awk934Rg= 28 | - secure: QbNAu0jCaKrwjJi7KZtYEBA/pYbTJ91Y1x/eLAJpsamswVOvwnThA/TLYuux+oiZQCiDUpBzP3oxksIrEEUAhl0lMtqRFY3MrcUr+si9NIjX8hmoFwkvZ5o1b7pmLF6Vz3rQeP/EWMLcljLzEwsrRXeK0Ei2E4vFpsg8yz1YXJg= 29 | - TRAVIS_NODE_VERSION="4" 30 | 31 | cache: 32 | directories: 33 | - $HOME/.sbt/0.13/dependency 34 | - $HOME/.sbt/boot/scala* 35 | - $HOME/.sbt/launchers 36 | - $HOME/.ivy2/cache 37 | - $HOME/.nvm 38 | 39 | before_cache: 40 | - du -h -d 1 $HOME/.ivy2/cache 41 | - du -h -d 2 $HOME/.sbt/ 42 | - find $HOME/.sbt -name "*.lock" -type f -delete 43 | - find $HOME/.ivy2/cache -name "ivydata-*.properties" -type f -delete 44 | -------------------------------------------------------------------------------- /bench/src/main/scala/cats/bench/FoldBench.scala: -------------------------------------------------------------------------------- 1 | package cats.bench 2 | 3 | import cats.data.Const 4 | import cats.instances.string._ 5 | import cats.instances.list._ 6 | import cats.{Foldable, Traverse} 7 | import org.openjdk.jmh.annotations.{Benchmark, Scope, State} 8 | 9 | @State(Scope.Benchmark) 10 | class FoldBench { 11 | 12 | val chars: List[String] = ('a' to 'z').map(_.toString).toList 13 | 14 | /** Benchmark fold of Foldable[List] */ 15 | @Benchmark 16 | def fold(): String = 17 | Foldable[List].fold(chars) 18 | 19 | /** Benchmark fold using traverse with Const */ 20 | @Benchmark 21 | def traverseConst(): String = 22 | Traverse[List].traverse[Const[String, ?], String, String](chars)(Const(_)).getConst 23 | 24 | } 25 | -------------------------------------------------------------------------------- /bench/src/main/scala/cats/bench/TrampolineBench.scala: -------------------------------------------------------------------------------- 1 | package cats.bench 2 | 3 | import org.openjdk.jmh.annotations.{Benchmark, Scope, State} 4 | 5 | import cats._ 6 | import cats.implicits._ 7 | import cats.free.Trampoline 8 | 9 | @State(Scope.Benchmark) 10 | class TrampolineBench { 11 | 12 | val N = 15 13 | 14 | @Benchmark 15 | def eval(): Int = evalFib(N).value 16 | 17 | def evalFib(n: Int): Eval[Int] = 18 | if (n < 2) Eval.now(n) else for { 19 | x <- Eval.defer(evalFib(n - 1)) 20 | y <- Eval.defer(evalFib(n - 2)) 21 | } yield x + y 22 | 23 | 24 | @Benchmark 25 | def trampoline(): Int = trampolineFib(N).run 26 | 27 | def trampolineFib(n: Int): Trampoline[Int] = 28 | if (n < 2) Trampoline.done(n) else for { 29 | x <- Trampoline.suspend(trampolineFib(n - 1)) 30 | y <- Trampoline.suspend(trampolineFib(n - 2)) 31 | } yield x + y 32 | 33 | // TailRec[A] only has .flatMap in 2.11. 34 | 35 | // @Benchmark 36 | // def stdlib(): Int = stdlibFib(N).result 37 | // 38 | // def stdlibFib(n: Int): TailCalls.TailRec[Int] = 39 | // if (n < 2) TailCalls.done(n) else for { 40 | // x <- TailCalls.tailcall(stdlibFib(n - 1)) 41 | // y <- TailCalls.tailcall(stdlibFib(n - 2)) 42 | // } yield x + y 43 | } 44 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/Alternative.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | import simulacrum.typeclass 4 | 5 | @typeclass trait Alternative[F[_]] extends Applicative[F] with MonoidK[F] { self => 6 | override def compose[G[_]: Applicative]: Alternative[λ[α => F[G[α]]]] = 7 | new ComposedAlternative[F, G] { 8 | val F = self 9 | val G = Applicative[G] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/Bimonad.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | import simulacrum.typeclass 4 | 5 | @typeclass trait Bimonad[F[_]] extends Monad[F] with Comonad[F] 6 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/Cartesian.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | import simulacrum.typeclass 4 | 5 | /** 6 | * [[Cartesian]] captures the idea of composing independent effectful values. 7 | * It is of particular interest when taken together with [[Functor]] - where [[Functor]] 8 | * captures the idea of applying a unary pure function to an effectful value, 9 | * calling `product` with `map` allows one to apply a function of arbitrary arity to multiple 10 | * independent effectful values. 11 | * 12 | * That same idea is also manifested in the form of [[Apply]], and indeed [[Apply]] extends both 13 | * [[Cartesian]] and [[Functor]] to illustrate this. 14 | */ 15 | @typeclass trait Cartesian[F[_]] { 16 | def product[A, B](fa: F[A], fb: F[B]): F[(A, B)] 17 | } 18 | 19 | object Cartesian extends CartesianArityFunctions with KernelCartesianInstances 20 | 21 | /** 22 | * Cartesian instances for types that are housed in Kernel and therefore 23 | * can't have instances for Cats type classes in their companion objects. 24 | */ 25 | private[cats] sealed trait KernelCartesianInstances { 26 | implicit val catsInvariantSemigroup: Cartesian[Semigroup] = InvariantMonoidal.catsInvariantMonoidalSemigroup 27 | implicit val catsInvariantMonoid: Cartesian[Monoid] = InvariantMonoidal.catsInvariantMonoidalMonoid 28 | implicit val catsCartesianEq: Cartesian[Eq] = ContravariantCartesian.catsContravariantCartesianEq 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/CoflatMap.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | import simulacrum.typeclass 4 | 5 | /** 6 | * `CoflatMap` is the dual of `FlatMap`. 7 | * 8 | * Must obey the laws in cats.laws.CoflatMapLaws 9 | */ 10 | @typeclass trait CoflatMap[F[_]] extends Functor[F] { 11 | 12 | /** 13 | * `coflatMap` is the dual of `flatMap` on `FlatMap`. It applies 14 | * a value in a context to a function that takes a value 15 | * in a context and returns a normal value. 16 | * 17 | * Example: 18 | * {{{ 19 | * scala> import cats.implicits._ 20 | * scala> import cats.CoflatMap 21 | * scala> val fa = Some(3) 22 | * scala> def f(a: Option[Int]): Int = a match { 23 | * | case Some(x) => 2 * x 24 | * | case None => 0 } 25 | * scala> CoflatMap[Option].coflatMap(fa)(f) 26 | * res0: Option[Int] = Some(6) 27 | * }}} 28 | */ 29 | def coflatMap[A, B](fa: F[A])(f: F[A] => B): F[B] 30 | 31 | /** 32 | * `coflatten` is the dual of `flatten` on `FlatMap`. Whereas flatten removes 33 | * a layer of `F`, coflatten adds a layer of `F` 34 | * 35 | * Example: 36 | * {{{ 37 | * scala> import cats.implicits._ 38 | * scala> import cats.CoflatMap 39 | * scala> val fa = Some(3) 40 | * fa: Option[Int] = Some(3) 41 | * scala> CoflatMap[Option].coflatten(fa) 42 | * res0: Option[Option[Int]] = Some(Some(3)) 43 | * }}} 44 | */ 45 | def coflatten[A](fa: F[A]): F[F[A]] = 46 | coflatMap(fa)(fa => fa) 47 | } 48 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/Comonad.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | import simulacrum.typeclass 4 | 5 | 6 | /** 7 | * Comonad 8 | * 9 | * Comonad is the dual of Monad. Whereas Monads allow for the composition of effectful functions, 10 | * Comonads allow for composition of functions that extract the value from their context. 11 | * 12 | * Must obey the laws defined in cats.laws.ComonadLaws. 13 | */ 14 | @typeclass trait Comonad[F[_]] extends CoflatMap[F] { 15 | 16 | /** 17 | * `extract` is the dual of `pure` on Monad (via `Applicative`) 18 | * and extracts the value from its context 19 | * 20 | * Example: 21 | * {{{ 22 | * scala> import cats.Id 23 | * scala> import cats.Comonad 24 | * scala> val id: Id[Int] = 3 25 | * scala> Comonad[Id].extract(id) 26 | * res0: cats.Id[Int] = 3 27 | * }}} 28 | */ 29 | def extract[A](x: F[A]): A 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/ContravariantCartesian.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | import functor.Contravariant 4 | import simulacrum.typeclass 5 | 6 | /** 7 | * [[ContravariantCartesian]] is nothing more than something both contravariant 8 | * and Cartesian. It comes up enough to be useful, and composes well 9 | */ 10 | @typeclass trait ContravariantCartesian[F[_]] extends Cartesian[F] with Contravariant[F] { self => 11 | override def composeFunctor[G[_]: Functor]: ContravariantCartesian[λ[α => F[G[α]]]] = 12 | new ComposedCartesian[F, G] { 13 | def F = self 14 | def G = Functor[G] 15 | } 16 | } 17 | 18 | object ContravariantCartesian extends KernelContravariantCartesianInstances 19 | 20 | private[cats] sealed trait KernelContravariantCartesianInstances { 21 | implicit val catsContravariantCartesianEq: ContravariantCartesian[Eq] = new ContravariantCartesian[Eq] { 22 | def contramap[A, B](fa: Eq[A])(fn: B => A): Eq[B] = fa.on(fn) 23 | def product[A, B](fa: Eq[A], fb: Eq[B]): Eq[(A, B)] = 24 | Eq.instance { (left, right) => fa.eqv(left._1, right._1) && fb.eqv(left._2, right._2) } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/Monad.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | import simulacrum.typeclass 4 | 5 | /** 6 | * Monad. 7 | * 8 | * Allows composition of dependent effectful functions. 9 | * 10 | * See: [[http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf Monads for functional programming]] 11 | * 12 | * Must obey the laws defined in cats.laws.MonadLaws. 13 | */ 14 | @typeclass trait Monad[F[_]] extends FlatMap[F] with Applicative[F] { 15 | override def map[A, B](fa: F[A])(f: A => B): F[B] = 16 | flatMap(fa)(a => pure(f(a))) 17 | 18 | /** 19 | * This is not stack safe if the monad is not trampolined, but it 20 | * is always lawful. It it better if you can find a stack safe way 21 | * to write this method (all cats types have a stack safe version 22 | * of this). When this method is safe you can find an `implicit r: RecursiveTailRecM`. 23 | */ 24 | protected def defaultTailRecM[A, B](a: A)(fn: A => F[Either[A, B]]): F[B] = 25 | flatMap(fn(a)) { 26 | case Right(b) => pure(b) 27 | case Left(nextA) => defaultTailRecM(nextA)(fn) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/MonadCombine.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | import simulacrum.typeclass 4 | 5 | /** 6 | * The combination of a Monad with a MonoidK 7 | */ 8 | @typeclass trait MonadCombine[F[_]] extends MonadFilter[F] with Alternative[F] { 9 | 10 | /** 11 | * Fold over the inner structure to combine all of the values with 12 | * our combine method inherited from MonoidK. The result is for us 13 | * to accumulate all of the "interesting" values of the inner G, so 14 | * if G is Option, we collect all the Some values, if G is Either, 15 | * we collect all the Right values, etc. 16 | */ 17 | def unite[G[_], A](fga: F[G[A]])(implicit G: Foldable[G]): F[A] = 18 | flatMap(fga) { ga => 19 | G.foldLeft(ga, empty[A])((acc, a) => combineK(acc, pure(a))) 20 | } 21 | 22 | /** Separate the inner foldable values into the "lefts" and "rights" */ 23 | def separate[G[_, _], A, B](fgab: F[G[A, B]])(implicit G: Bifoldable[G]): (F[A], F[B]) = { 24 | val as = flatMap(fgab)(gab => G.bifoldMap(gab)(pure, _ => empty[A])(algebra[A])) 25 | val bs = flatMap(fgab)(gab => G.bifoldMap(gab)(_ => empty[B], pure)(algebra[B])) 26 | (as, bs) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/MonadError.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | /** 4 | * A monad that also allows you to raise and or handle an error value. 5 | * 6 | * This type class allows one to abstract over error-handling monads. 7 | */ 8 | trait MonadError[F[_], E] extends ApplicativeError[F, E] with Monad[F] { 9 | 10 | /** 11 | * Turns a successful value into an error if it does not satisfy a given predicate. 12 | */ 13 | def ensure[A](fa: F[A])(error: => E)(predicate: A => Boolean): F[A] = 14 | flatMap(fa)(a => if (predicate(a)) pure(a) else raiseError(error)) 15 | 16 | } 17 | 18 | object MonadError { 19 | def apply[F[_], E](implicit F: MonadError[F, E]): MonadError[F, E] = F 20 | } 21 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/MonadFilter.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | import simulacrum.typeclass 4 | 5 | /** 6 | * a Monad equipped with an additional method which allows us to 7 | * create an "empty" value for the Monad (for whatever "empty" makes 8 | * sense for that particular monad). This is of particular interest to 9 | * us since it allows us to add a `filter` method to a Monad, which is 10 | * used when pattern matching or using guards in for comprehensions. 11 | */ 12 | @typeclass trait MonadFilter[F[_]] extends Monad[F] with FunctorFilter[F] { 13 | 14 | def empty[A]: F[A] 15 | 16 | override def mapFilter[A, B](fa: F[A])(f: A => Option[B]): F[B] = 17 | flatMap(fa)(a => f(a).fold(empty[B])(pure)) 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/MonadReader.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | /** A monad that has the ability to read from an environment. */ 4 | trait MonadReader[F[_], R] extends Monad[F] { 5 | /** Get the environment */ 6 | def ask: F[R] 7 | 8 | /** Modify the environment */ 9 | def local[A](f: R => R)(fa: F[A]): F[A] 10 | } 11 | 12 | object MonadReader { 13 | def apply[F[_], R](implicit F: MonadReader[F, R]): MonadReader[F, R] = F 14 | } 15 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/MonadState.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | /** A monad that can read, update, and pass along state (e.g. `StateT`). 4 | * 5 | * A common use case for `MonadState` is for syntax, especially when 6 | * dealing with large monad transformer stacks. For instance: 7 | * 8 | * {{{ 9 | * val M = MonadState[StateT[List, Int, ?], Int] 10 | * import M._ 11 | * 12 | * for { 13 | * g <- get 14 | * _ <- set(g + 1) 15 | * r <- inspect(_ * 100) 16 | * } yield r 17 | * }}} 18 | */ 19 | trait MonadState[F[_], S] extends Monad[F] { 20 | def get: F[S] 21 | 22 | def set(s: S): F[Unit] 23 | 24 | def modify(f: S => S): F[Unit] = flatMap(get)(s => set(f(s))) 25 | 26 | def inspect[A](f: S => A): F[A] = map(get)(f) 27 | } 28 | 29 | object MonadState { 30 | def apply[F[_], S](implicit F: MonadState[F, S]): MonadState[F, S] = F 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/MonadWriter.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | /** A monad that support monoidal accumulation (e.g. logging List[String]) */ 4 | trait MonadWriter[F[_], W] extends Monad[F] { 5 | /** Lift a writer action into the effect */ 6 | def writer[A](aw: (W, A)): F[A] 7 | 8 | /** Run the effect and pair the accumulator with the result */ 9 | def listen[A](fa: F[A]): F[(W, A)] 10 | 11 | /** Apply the effectful function to the accumulator */ 12 | def pass[A](fa: F[(W => W, A)]): F[A] 13 | 14 | /** Lift the log into the effect */ 15 | def tell(w: W): F[Unit] = writer((w, ())) 16 | 17 | /** Pair the value with an inspection of the accumulator */ 18 | def listens[A, B](fa: F[A])(f: W => B): F[(B, A)] = 19 | map(listen(fa)) { case (w, a) => (f(w), a) } 20 | 21 | /** Modify the accumulator */ 22 | def censor[A](fa: F[A])(f: W => W): F[A] = 23 | flatMap(listen(fa)) { case (w, a) => writer((f(w), a)) } 24 | } 25 | 26 | object MonadWriter { 27 | def apply[F[_], W](implicit F: MonadWriter[F, W]): MonadWriter[F, W] = F 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/MonoidK.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | import simulacrum.typeclass 4 | 5 | /** 6 | * MonoidK is a universal monoid which operates on kinds. 7 | * 8 | * This type class is useful when its type parameter F[_] has a 9 | * structure that can be combined for any particular type, and which 10 | * also has an "empty" representation. Thus, MonoidK is like a Monoid 11 | * for kinds (i.e. parameterized types). 12 | * 13 | * A MonoidK[F] can produce a Monoid[F[A]] for any type A. 14 | * 15 | * Here's how to distinguish Monoid and MonoidK: 16 | * 17 | * - Monoid[A] allows A values to be combined, and also means there 18 | * is an "empty" A value that functions as an identity. 19 | * 20 | * - MonoidK[F] allows two F[A] values to be combined, for any A. It 21 | * also means that for any A, there is an "empty" F[A] value. The 22 | * combination operation and empty value just depend on the 23 | * structure of F, but not on the structure of A. 24 | */ 25 | @typeclass trait MonoidK[F[_]] extends SemigroupK[F] { self => 26 | 27 | /** 28 | * Given a type A, create an "empty" F[A] value. 29 | */ 30 | def empty[A]: F[A] 31 | 32 | /** 33 | * Given a type A, create a concrete Monoid[F[A]]. 34 | */ 35 | override def algebra[A]: Monoid[F[A]] = 36 | new Monoid[F[A]] { 37 | def empty: F[A] = self.empty 38 | def combine(x: F[A], y: F[A]): F[A] = self.combineK(x, y) 39 | } 40 | 41 | override def compose[G[_]]: MonoidK[λ[α => F[G[α]]]] = 42 | new ComposedMonoidK[F, G] { 43 | val F = self 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/NotNull.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | /** 4 | * An instance of `NotNull[A]` indicates that `A` does not have a static type 5 | * of `Null`. 6 | * 7 | * This can be useful in preventing `Null` from being inferred when a type 8 | * parameter is omitted. 9 | * 10 | * This trait is used along with ambiguous implicits to achieve the goal of 11 | * preventing inference of `Null`. This ambiguous implicit trick has been used 12 | * in the Scala community for some time. [[https://gist.github.com/milessabin/de58f3ba7024d51dcc1a Here]] 13 | * is an early example of such a trick being used in a similar way to prevent a 14 | * `Nothing` type. 15 | */ 16 | sealed trait NotNull[A] 17 | 18 | object NotNull { 19 | /** 20 | * Since NotNull is just a marker trait with no functionality, it's safe to 21 | * reuse a single instance of it. This helps prevent unnecessary allocations. 22 | */ 23 | private[this] val singleton: NotNull[Any] = new NotNull[Any] {} 24 | 25 | private[this] def ambiguousException: Exception = new Exception("An instance of NotNull[Null] was used. This should never happen. Both ambiguous NotNull[Null] instances should always be in scope if one of them is.") 26 | 27 | implicit def `If you are seeing this, you probably need to add an explicit type parameter somewhere, because Null is being inferred.`: NotNull[Null] = throw ambiguousException 28 | 29 | implicit def catsAmbiguousNotNullNull2: NotNull[Null] = throw ambiguousException 30 | 31 | implicit def catsNotNullForA[A]: NotNull[A] = singleton.asInstanceOf[NotNull[A]] 32 | } 33 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/RecursiveTailRecM.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | import java.io.Serializable 4 | /** 5 | * This is a marker type that promises that the method 6 | * .tailRecM for this type is stack-safe for arbitrary recursion. 7 | */ 8 | trait RecursiveTailRecM[F[_]] extends Serializable { 9 | /* 10 | * you can call RecursiveTailRecM[F].sameType(Monad[F]).tailRec 11 | * to have a static check that the types agree 12 | * for safer usage of tailRecM 13 | */ 14 | final def sameType[M[_[_]]](m: M[F]): M[F] = m 15 | } 16 | 17 | object RecursiveTailRecM { 18 | private[this] val singleton: RecursiveTailRecM[Id] = new RecursiveTailRecM[Id] { } 19 | 20 | def apply[F[_]](implicit r: RecursiveTailRecM[F]): RecursiveTailRecM[F] = r 21 | 22 | def create[F[_]]: RecursiveTailRecM[F] = 23 | singleton.asInstanceOf[RecursiveTailRecM[F]] 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/SemigroupK.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | import simulacrum.typeclass 4 | 5 | /** 6 | * SemigroupK is a universal semigroup which operates on kinds. 7 | * 8 | * This type class is useful when its type parameter F[_] has a 9 | * structure that can be combined for any particular type. Thus, 10 | * SemigroupK is like a Semigroup for kinds (i.e. parameterized 11 | * types). 12 | * 13 | * A SemigroupK[F] can produce a Semigroup[F[A]] for any type A. 14 | * 15 | * Here's how to distinguish Semigroup and SemigroupK: 16 | * 17 | * - Semigroup[A] allows two A values to be combined. 18 | * 19 | * - SemigroupK[F] allows two F[A] values to be combined, for any A. 20 | * The combination operation just depends on the structure of F, 21 | * but not the structure of A. 22 | */ 23 | @typeclass trait SemigroupK[F[_]] { self => 24 | 25 | /** 26 | * Combine two F[A] values. 27 | */ 28 | @simulacrum.op("<+>", alias = true) 29 | def combineK[A](x: F[A], y: F[A]): F[A] 30 | 31 | /** 32 | * Given a type A, create a concrete Semigroup[F[A]]. 33 | */ 34 | def algebra[A]: Semigroup[F[A]] = 35 | new Semigroup[F[A]] { 36 | def combine(x: F[A], y: F[A]): F[A] = self.combineK(x, y) 37 | } 38 | 39 | def compose[G[_]]: SemigroupK[λ[α => F[G[α]]]] = 40 | new ComposedSemigroupK[F, G] { 41 | val F = self 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/Show.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | import simulacrum.typeclass 4 | import cats.functor.Contravariant 5 | 6 | /** 7 | * A type class to provide textual representation. It is meant to be a 8 | * better "toString". Whereas toString exists for any Object, 9 | * regardless of whether or not the creator of the class explicitly 10 | * made a toString method, a Show instance will only exist if someone 11 | * explicitly provided one. 12 | */ 13 | @typeclass trait Show[T] { 14 | def show(f: T): String 15 | } 16 | 17 | object Show { 18 | /** creates an instance of [[Show]] using the provided function */ 19 | def show[A](f: A => String): Show[A] = new Show[A] { 20 | def show(a: A): String = f(a) 21 | } 22 | 23 | /** creates an instance of [[Show]] using object toString */ 24 | def fromToString[A]: Show[A] = new Show[A] { 25 | def show(a: A): String = a.toString 26 | } 27 | 28 | implicit val catsContravariantForShow: Contravariant[Show] = new Contravariant[Show] { 29 | def contramap[A, B](fa: Show[A])(f: B => A): Show[B] = 30 | show[B](fa.show _ compose f) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/TransLift.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | /** 4 | * A type class which abstracts over the ability to lift an M[A] into a 5 | * MonadTransformer 6 | */ 7 | trait TransLift[MT[_[_], _]] { 8 | 9 | /** 10 | * The type class which constrains liftT as a function of the type 11 | * constructor it is given. A safe "identity" value for this type 12 | * if your transformer does not constrain its lifted effects would 13 | * be `type TC[M[_]] = Trivial`. A more common constraint might be 14 | * `type TC[M[_]] = Monad[M]`. 15 | */ 16 | type TC[M[_]] 17 | 18 | /** 19 | * Lift a value of type M[A] into a monad transformer MT[M, A] 20 | */ 21 | def liftT[M[_]: TC, A](ma: M[A]): MT[M, A] 22 | } 23 | 24 | object TransLift { 25 | type Aux[MT[_[_], _], TC0[_[_]]] = TransLift[MT] { type TC[M[_]] = TC0[M] } 26 | type AuxId[MT[_[_], _]] = Aux[MT, Trivial.PH1] 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/Trivial.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | /** 4 | * The "Unit type class". The only instance of `Trivial` is given by 5 | * `Trivial.manifest`, and this instance is guaranteed to be in the 6 | * implicit scope. Several convenience type aliases are provided in 7 | * companion object, covering a few common use cases and avoiding the 8 | * need for unnecessary lambdas (e.g. if you want a trivial type class 9 | * instance for a type constructor, you should use `Trivial.PH1`). 10 | */ 11 | sealed trait Trivial 12 | 13 | object Trivial { 14 | type P1[A] = Trivial 15 | type PH1[F[_]] = Trivial 16 | type P1H1[F[_], A] = Trivial 17 | type P2[A, B] = Trivial 18 | type P2H1[F[_], A, B] = Trivial 19 | type P3[A, B, C] = Trivial 20 | type P3H1[F[_], A, B, C] = Trivial 21 | 22 | implicit val catsTrivialInstance: Trivial = new Trivial {} 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/arrow/Arrow.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package arrow 3 | 4 | import cats.functor.Strong 5 | 6 | import simulacrum.typeclass 7 | 8 | @typeclass trait Arrow[F[_, _]] extends Split[F] with Strong[F] with Category[F] { self => 9 | 10 | /** 11 | * Lift a function into the context of an Arrow 12 | */ 13 | def lift[A, B](f: A => B): F[A, B] 14 | 15 | override def dimap[A, B, C, D](fab: F[A, B])(f: C => A)(g: B => D): F[C, D] = 16 | compose(lift(g), andThen(lift(f), fab)) 17 | 18 | override def second[A, B, C](fa: F[A, B]): F[(C, A), (C, B)] = { 19 | def swap[X, Y]: F[(X, Y), (Y, X)] = lift[(X, Y), (Y, X)] { case (x, y) => (y, x) } 20 | compose(swap, compose(first[A, B, C](fa), swap)) 21 | } 22 | 23 | override def split[A, B, C, D](f: F[A, B], g: F[C, D]): F[(A, C), (B, D)] = 24 | andThen(first(f), second(g)) 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/arrow/Category.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package arrow 3 | 4 | import simulacrum.typeclass 5 | 6 | /** 7 | * Must obey the laws defined in cats.laws.CategoryLaws. 8 | */ 9 | @typeclass trait Category[F[_, _]] extends Compose[F] { self => 10 | 11 | def id[A]: F[A, A] 12 | 13 | override def algebraK: MonoidK[λ[α => F[α, α]]] = 14 | new MonoidK[λ[α => F[α, α]]] { 15 | def empty[A]: F[A, A] = id 16 | def combineK[A](f1: F[A, A], f2: F[A, A]): F[A, A] = self.compose(f1, f2) 17 | } 18 | 19 | override def algebra[A]: Monoid[F[A, A]] = 20 | new Monoid[F[A, A]] { 21 | def empty: F[A, A] = id 22 | def combine(f1: F[A, A], f2: F[A, A]): F[A, A] = self.compose(f1, f2) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/arrow/Choice.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package arrow 3 | 4 | import simulacrum.typeclass 5 | 6 | @typeclass trait Choice[F[_, _]] extends Category[F] { 7 | /** 8 | * Given two `F`s (`f` and `g`) with a common target type, create a new `F` 9 | * with the same target type, but with a source type of either `f`'s source 10 | * type OR `g`'s source type. 11 | * 12 | * Example: 13 | * {{{ 14 | * scala> import cats.implicits._ 15 | * scala> val b: Boolean => String = _ + " is a boolean" 16 | * scala> val i: Int => String = _ + " is an integer" 17 | * scala> val f: (Either[Boolean, Int]) => String = Choice[Function1].choice(b, i) 18 | * 19 | * scala> f(Right(3)) 20 | * res0: String = 3 is an integer 21 | * 22 | * scala> f(Left(false)) 23 | * res0: String = false is a boolean 24 | * }}} 25 | */ 26 | def choice[A, B, C](f: F[A, C], g: F[B, C]): F[Either[A, B], C] 27 | 28 | /** 29 | * An `F` that, given a source `A` on either the right or left side, will 30 | * return that same `A` object. 31 | * 32 | * Example: 33 | * {{{ 34 | * scala> import cats.implicits._ 35 | * scala> val f: (Either[Int, Int]) => Int = Choice[Function1].codiagonal[Int] 36 | * 37 | * scala> f(Right(3)) 38 | * res0: Int = 3 39 | * 40 | * scala> f(Left(3)) 41 | * res1: Int = 3 42 | * }}} 43 | */ 44 | def codiagonal[A]: F[Either[A, A], A] = choice(id, id) 45 | } 46 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/arrow/Compose.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package arrow 3 | 4 | import simulacrum.typeclass 5 | 6 | /** 7 | * Must obey the laws defined in cats.laws.ComposeLaws. 8 | */ 9 | @typeclass trait Compose[F[_, _]] { self => 10 | def compose[A, B, C](f: F[B, C], g: F[A, B]): F[A, C] 11 | 12 | def andThen[A, B, C](f: F[A, B], g: F[B, C]): F[A, C] = 13 | compose(g, f) 14 | 15 | def algebraK: SemigroupK[λ[α => F[α, α]]] = 16 | new SemigroupK[λ[α => F[α, α]]] { 17 | def combineK[A](f1: F[A, A], f2: F[A, A]): F[A, A] = self.compose(f1, f2) 18 | } 19 | 20 | def algebra[A]: Semigroup[F[A, A]] = 21 | new Semigroup[F[A, A]] { 22 | def combine(f1: F[A, A], f2: F[A, A]): F[A, A] = self.compose(f1, f2) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/arrow/FunctionK.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package arrow 3 | 4 | import cats.data. Coproduct 5 | 6 | trait FunctionK[F[_], G[_]] extends Serializable { self => 7 | def apply[A](fa: F[A]): G[A] 8 | 9 | def compose[E[_]](f: FunctionK[E, F]): FunctionK[E, G] = 10 | new FunctionK[E, G] { 11 | def apply[A](fa: E[A]): G[A] = self.apply(f(fa)) 12 | } 13 | 14 | def andThen[H[_]](f: FunctionK[G, H]): FunctionK[F, H] = 15 | f.compose(self) 16 | 17 | def or[H[_]](h: FunctionK[H, G]): FunctionK[Coproduct[F, H, ?], G] = 18 | new FunctionK[Coproduct[F, H, ?], G] { 19 | def apply[A](fa: Coproduct[F, H, A]): G[A] = fa.run match { 20 | case Left(ff) => self(ff) 21 | case Right(gg) => h(gg) 22 | } 23 | } 24 | } 25 | 26 | object FunctionK { 27 | def id[F[_]]: FunctionK[F, F] = 28 | new FunctionK[F, F] { 29 | def apply[A](fa: F[A]): F[A] = fa 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/arrow/Split.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package arrow 3 | 4 | import simulacrum.typeclass 5 | 6 | @typeclass trait Split[F[_, _]] extends Compose[F] { self => 7 | 8 | /** 9 | * Create a new `F` that splits its input between `f` and `g` 10 | * and combines the output of each. 11 | * 12 | * Example: 13 | * {{{ 14 | * scala> import cats.implicits._ 15 | * scala> import cats.arrow.Split 16 | * scala> val toLong: Int => Long = _.toLong 17 | * scala> val toDouble: Float => Double = _.toDouble 18 | * scala> val f: ((Int, Float)) => (Long, Double) = Split[Function1].split(toLong, toDouble) 19 | * scala> f((3, 4.0f)) 20 | * res0: (Long, Double) = (3,4.0) 21 | * }}} 22 | */ 23 | def split[A, B, C, D](f: F[A, B], g: F[C, D]): F[(A, C), (B, D)] 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/data/package.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | package object data { 4 | type NonEmptyStream[A] = OneAnd[Stream, A] 5 | type ValidatedNel[E, A] = Validated[NonEmptyList[E], A] 6 | 7 | def NonEmptyStream[A](head: A, tail: Stream[A] = Stream.empty): NonEmptyStream[A] = 8 | OneAnd(head, tail) 9 | def NonEmptyStream[A](head: A, tail: A*): NonEmptyStream[A] = 10 | OneAnd(head, tail.toStream) 11 | 12 | type ReaderT[F[_], A, B] = Kleisli[F, A, B] 13 | val ReaderT = Kleisli 14 | 15 | type Reader[A, B] = ReaderT[Id, A, B] 16 | object Reader { 17 | def apply[A, B](f: A => B): Reader[A, B] = ReaderT[Id, A, B](f) 18 | } 19 | 20 | type Writer[L, V] = WriterT[Id, L, V] 21 | object Writer { 22 | def apply[L, V](l: L, v: V): WriterT[Id, L, V] = WriterT[Id, L, V]((l, v)) 23 | 24 | def value[L:Monoid, V](v: V): Writer[L, V] = WriterT.value(v) 25 | 26 | def tell[L](l: L): Writer[L, Unit] = WriterT.tell(l) 27 | } 28 | 29 | type State[S, A] = StateT[Eval, S, A] 30 | object State extends StateFunctions 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/functor/Invariant.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package functor 3 | 4 | import simulacrum.typeclass 5 | 6 | /** 7 | * Must obey the laws defined in cats.laws.InvariantLaws. 8 | */ 9 | @typeclass trait Invariant[F[_]] { self => 10 | def imap[A, B](fa: F[A])(f: A => B)(g: B => A): F[B] 11 | 12 | def compose[G[_]: Invariant]: Invariant[λ[α => F[G[α]]]] = 13 | new ComposedInvariant[F, G] { 14 | val F = self 15 | val G = Invariant[G] 16 | } 17 | 18 | def composeFunctor[G[_]: Functor]: Invariant[λ[α => F[G[α]]]] = 19 | new ComposedInvariantCovariant[F, G] { 20 | val F = self 21 | val G = Functor[G] 22 | } 23 | 24 | def composeContravariant[G[_]: Contravariant]: Invariant[λ[α => F[G[α]]]] = 25 | new ComposedInvariantContravariant[F, G] { 26 | val F = self 27 | val G = Contravariant[G] 28 | } 29 | } 30 | 31 | object Invariant extends KernelInvariantInstances 32 | 33 | /** 34 | * Invariant instances for types that are housed in cats.kernel and therefore 35 | * can't have instances for this type class in their companion objects. 36 | */ 37 | private[functor] sealed trait KernelInvariantInstances { 38 | implicit val catsFunctorInvariantForSemigroup: Invariant[Semigroup] = InvariantMonoidal.catsInvariantMonoidalSemigroup 39 | implicit val catsFunctorInvariantForMonoid: Invariant[Monoid] = InvariantMonoidal.catsInvariantMonoidalMonoid 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/functor/Profunctor.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package functor 3 | 4 | import simulacrum.typeclass 5 | 6 | /** 7 | * A [[Profunctor]] is a [[Contravariant]] functor on its first type parameter 8 | * and a [[Functor]] on its second type parameter. 9 | * 10 | * Must obey the laws defined in cats.laws.ProfunctorLaws. 11 | */ 12 | @typeclass trait Profunctor[F[_, _]] { self => 13 | 14 | /** 15 | * Contramap on the first type parameter and map on the second type parameter 16 | * 17 | * Example: 18 | * {{{ 19 | * scala> import cats.implicits._ 20 | * scala> import cats.functor.Profunctor 21 | * scala> val fab: Double => Double = x => x + 0.3 22 | * scala> val f: Int => Double = x => x.toDouble / 2 23 | * scala> val g: Double => Double = x => x * 3 24 | * scala> val h = Profunctor[Function1].dimap(fab)(f)(g) 25 | * scala> h(3) 26 | * res0: Double = 5.4 27 | * }}} 28 | */ 29 | def dimap[A, B, C, D](fab: F[A, B])(f: C => A)(g: B => D): F[C, D] 30 | 31 | /** 32 | * contramap on the first type parameter 33 | */ 34 | def lmap[A, B, C](fab: F[A, B])(f: C => A): F[C, B] = 35 | dimap(fab)(f)(identity) 36 | 37 | /** 38 | * map on the second type parameter 39 | */ 40 | def rmap[A, B, C](fab: F[A, B])(f: B => C): F[A, C] = 41 | dimap[A, B, A, C](fab)(identity)(f) 42 | } 43 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/functor/Strong.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package functor 3 | 4 | import simulacrum.typeclass 5 | 6 | /** 7 | * Must obey the laws defined in cats.laws.StrongLaws. 8 | */ 9 | @typeclass trait Strong[F[_, _]] extends Profunctor[F] { 10 | 11 | /** 12 | * Create a new `F` that takes two inputs, but only modifies the first input 13 | * 14 | * Example: 15 | * {{{ 16 | * scala> import cats.implicits._ 17 | * scala> import cats.functor.Strong 18 | * scala> val f: Int => Int = _ * 2 19 | * scala> val fab = Strong[Function1].first[Int,Int,Int](f) 20 | * scala> fab((2,3)) 21 | * res0: (Int, Int) = (4,3) 22 | * }}} 23 | */ 24 | def first[A, B, C](fa: F[A, B]): F[(A, C), (B, C)] 25 | 26 | /** 27 | * Create a new `F` that takes two inputs, but only modifies the second input 28 | * 29 | * Example: 30 | * {{{ 31 | * scala> import cats.implicits._ 32 | * scala> import cats.functor.Strong 33 | * scala> val f: Int => Int = _ * 2 34 | * scala> val fab = Strong[Function1].second[Int,Int,Int](f) 35 | * scala> fab((2,3)) 36 | * res0: (Int, Int) = (2,6) 37 | * }}} 38 | */ 39 | def second[A, B, C](fa: F[A, B]): F[(C, A), (C, B)] 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/implicits/package.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | object implicits extends syntax.AllSyntax with instances.AllInstances 4 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/instances/all.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package instances 3 | 4 | trait AllInstances 5 | extends FunctionInstances 6 | with StringInstances 7 | with EitherInstances 8 | with ListInstances 9 | with OptionInstances 10 | with SetInstances 11 | with StreamInstances 12 | with VectorInstances 13 | with AnyValInstances 14 | with MapInstances 15 | with BigIntInstances 16 | with BigDecimalInstances 17 | with FutureInstances 18 | with TryInstances 19 | with TupleInstances 20 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/instances/bigDecimal.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package instances 3 | 4 | trait BigDecimalInstances extends cats.kernel.instances.BigDecimalInstances { 5 | implicit val catsStdShowForBigDecimal: Show[BigDecimal] = 6 | Show.fromToString[BigDecimal] 7 | } 8 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/instances/bigInt.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package instances 3 | 4 | trait BigIntInstances extends cats.kernel.instances.BigIntInstances { 5 | implicit val catsStdShowForBigInt: Show[BigInt] = 6 | Show.fromToString[BigInt] 7 | } 8 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/instances/package.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | package object instances { 4 | object all extends AllInstances 5 | 6 | object either extends EitherInstances 7 | object function extends FunctionInstances 8 | 9 | object list extends ListInstances 10 | object option extends OptionInstances 11 | object set extends SetInstances 12 | object stream extends StreamInstances 13 | object vector extends VectorInstances 14 | object map extends MapInstances 15 | object future extends FutureInstances 16 | 17 | object string extends StringInstances 18 | object int extends IntInstances 19 | object byte extends ByteInstances 20 | object long extends LongInstances 21 | object char extends CharInstances 22 | object short extends ShortInstances 23 | object float extends FloatInstances 24 | object double extends DoubleInstances 25 | object boolean extends BooleanInstances 26 | object unit extends UnitInstances 27 | 28 | object bigInt extends BigIntInstances 29 | object bigDecimal extends BigDecimalInstances 30 | 31 | object try_ extends TryInstances 32 | object tuple extends TupleInstances 33 | } 34 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/instances/set.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package instances 3 | 4 | import cats.syntax.show._ 5 | 6 | trait SetInstances extends cats.kernel.instances.SetInstances { 7 | 8 | implicit val catsStdInstancesForSet: Foldable[Set] with MonoidK[Set] = 9 | new Foldable[Set] with MonoidK[Set] { 10 | 11 | def empty[A]: Set[A] = Set.empty[A] 12 | 13 | def combineK[A](x: Set[A], y: Set[A]): Set[A] = x | y 14 | 15 | def foldLeft[A, B](fa: Set[A], b: B)(f: (B, A) => B): B = 16 | fa.foldLeft(b)(f) 17 | 18 | def foldRight[A, B](fa: Set[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = 19 | Foldable.iterateRight(fa.iterator, lb)(f) 20 | 21 | override def size[A](fa: Set[A]): Long = fa.size.toLong 22 | 23 | override def exists[A](fa: Set[A])(p: A => Boolean): Boolean = 24 | fa.exists(p) 25 | 26 | override def forall[A](fa: Set[A])(p: A => Boolean): Boolean = 27 | fa.forall(p) 28 | 29 | override def isEmpty[A](fa: Set[A]): Boolean = fa.isEmpty 30 | } 31 | 32 | implicit def catsStdShowForSet[A:Show]: Show[Set[A]] = new Show[Set[A]] { 33 | def show(fa: Set[A]): String = 34 | fa.toIterator.map(_.show).mkString("Set(", ", ", ")") 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/instances/string.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package instances 3 | 4 | trait StringInstances extends cats.kernel.instances.StringInstances { 5 | implicit val catsStdShowForString: Show[String] = 6 | Show.fromToString[String] 7 | } 8 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/all.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | trait AllSyntax 5 | extends ApplicativeSyntax 6 | with ApplicativeErrorSyntax 7 | with ApplySyntax 8 | with BifunctorSyntax 9 | with BifoldableSyntax 10 | with BitraverseSyntax 11 | with CartesianSyntax 12 | with CoflatMapSyntax 13 | with ComonadSyntax 14 | with ComposeSyntax 15 | with ContravariantSyntax 16 | with CoproductSyntax 17 | with EitherSyntax 18 | with EqSyntax 19 | with FlatMapSyntax 20 | with FoldableSyntax 21 | with FunctorSyntax 22 | with FunctorFilterSyntax 23 | with GroupSyntax 24 | with InvariantSyntax 25 | with ListSyntax 26 | with MonadCombineSyntax 27 | with MonadErrorSyntax 28 | with MonadFilterSyntax 29 | with MonoidSyntax 30 | with OptionSyntax 31 | with OrderSyntax 32 | with PartialOrderSyntax 33 | with ProfunctorSyntax 34 | with ReducibleSyntax 35 | with SemigroupSyntax 36 | with SemigroupKSyntax 37 | with Show.ToShowOps 38 | with SplitSyntax 39 | with StrongSyntax 40 | with TransLiftSyntax 41 | with TraverseFilterSyntax 42 | with TraverseSyntax 43 | with TupleSyntax 44 | with ValidatedSyntax 45 | with WriterSyntax 46 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/applicative.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | trait ApplicativeSyntax { 5 | implicit def catsSyntaxApplicativeId[A](a: A): ApplicativeIdOps[A] = new ApplicativeIdOps[A](a) 6 | } 7 | 8 | final class ApplicativeIdOps[A](val a: A) extends AnyVal { 9 | def pure[F[_]](implicit F: Applicative[F]): F[A] = F.pure(a) 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/applicativeError.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | import cats.data.EitherT 5 | 6 | trait ApplicativeErrorSyntax { 7 | implicit def catsSyntaxApplicativeErrorId[E](e: E): ApplicativeErrorIdOps[E] = 8 | new ApplicativeErrorIdOps(e) 9 | 10 | implicit def catsSyntaxApplicativeError[F[_], E, A](fa: F[A])(implicit F: ApplicativeError[F, E]): ApplicativeErrorOps[F, E, A] = 11 | new ApplicativeErrorOps[F, E, A](fa) 12 | 13 | } 14 | 15 | final class ApplicativeErrorIdOps[E](e: E) { 16 | def raiseError[F[_], A](implicit F: ApplicativeError[F, E]): F[A] = 17 | F.raiseError(e) 18 | } 19 | 20 | final class ApplicativeErrorOps[F[_], E, A](fa: F[A])(implicit F: ApplicativeError[F, E]) { 21 | def handleError(f: E => A): F[A] = 22 | F.handleError(fa)(f) 23 | 24 | def handleErrorWith(f: E => F[A]): F[A] = 25 | F.handleErrorWith(fa)(f) 26 | 27 | def attempt: F[Either[E, A]] = 28 | F.attempt(fa) 29 | 30 | def attemptT: EitherT[F, E, A] = 31 | F.attemptT(fa) 32 | 33 | def recover(pf: PartialFunction[E, A]): F[A] = 34 | F.recover(fa)(pf) 35 | 36 | def recoverWith(pf: PartialFunction[E, F[A]]): F[A] = 37 | F.recoverWith(fa)(pf) 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/apply.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | private[syntax] trait ApplySyntax1 { 5 | implicit def catsSyntaxUApply[FA](fa: FA)(implicit U: Unapply[Apply, FA]): Apply.Ops[U.M, U.A] = 6 | new Apply.Ops[U.M, U.A] { 7 | val self = U.subst(fa) 8 | val typeClassInstance = U.TC 9 | } 10 | } 11 | 12 | trait ApplySyntax extends ApplySyntax1 { 13 | implicit def catsSyntaxApply[F[_], A](fa: F[A])(implicit F: Apply[F]): Apply.Ops[F, A] = 14 | new Apply.Ops[F, A] { 15 | val self = fa 16 | val typeClassInstance = F 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/bifoldable.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | trait BifoldableSyntax extends Bifoldable.ToBifoldableOps 5 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/bifunctor.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | import cats.functor.Bifunctor 5 | 6 | trait BifunctorSyntax extends Bifunctor.ToBifunctorOps 7 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/bitraverse.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | trait BitraverseSyntax extends BitraverseSyntax1 { 5 | implicit def catsSyntaxBitraverse[F[_, _]: Bitraverse, A, B](fab: F[A, B]): BitraverseOps[F, A, B] = 6 | new BitraverseOps[F, A, B](fab) 7 | } 8 | 9 | private[syntax] trait BitraverseSyntax1 { 10 | implicit def catsSyntaxNestedBitraverse[F[_, _]: Bitraverse, G[_], A, B](fgagb: F[G[A], G[B]]): NestedBitraverseOps[F, G, A, B] = 11 | new NestedBitraverseOps[F, G, A, B](fgagb) 12 | } 13 | 14 | final class BitraverseOps[F[_, _], A, B](fab: F[A, B])(implicit F: Bitraverse[F]) { 15 | def bitraverse[G[_]: Applicative, C, D](f: A => G[C], g: B => G[D]): G[F[C, D]] = 16 | F.bitraverse(fab)(f, g) 17 | } 18 | 19 | final class NestedBitraverseOps[F[_, _], G[_], A, B](fgagb: F[G[A], G[B]])(implicit F: Bitraverse[F]) { 20 | def bisequence(implicit G: Applicative[G]): G[F[A, B]] = 21 | F.bisequence(fgagb) 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/cartesian.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | private[syntax] trait CartesianSyntax1 { 5 | implicit def catsSyntaxUCartesian[FA](fa: FA)(implicit U: Unapply[Cartesian, FA]): CartesianOps[U.M, U.A] = 6 | new CartesianOps[U.M, U.A] { 7 | val self = U.subst(fa) 8 | val typeClassInstance = U.TC 9 | } 10 | } 11 | 12 | trait CartesianSyntax extends CartesianSyntax1 { 13 | implicit def catsSyntaxCartesian[F[_], A](fa: F[A])(implicit F: Cartesian[F]): CartesianOps[F, A] = 14 | new CartesianOps[F, A] { 15 | val self = fa 16 | val typeClassInstance = F 17 | } 18 | } 19 | 20 | abstract class CartesianOps[F[_], A] extends Cartesian.Ops[F, A] { 21 | def |@|[B](fb: F[B]): CartesianBuilder[F]#CartesianBuilder2[A, B] = 22 | new CartesianBuilder[F] |@| self |@| fb 23 | 24 | def *>[B](fb: F[B])(implicit F: Functor[F]): F[B] = F.map(typeClassInstance.product(self, fb)) { case (a, b) => b } 25 | 26 | def <*[B](fb: F[B])(implicit F: Functor[F]): F[A] = F.map(typeClassInstance.product(self, fb)) { case (a, b) => a } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/coflatMap.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | private[syntax] trait CoflatMapSyntax1 { 5 | implicit def catsSyntaxUCoflatMap[FA](fa: FA)(implicit U: Unapply[CoflatMap, FA]): CoflatMap.Ops[U.M, U.A] = new CoflatMap.Ops[U.M, U.A] { 6 | val self = U.subst(fa) 7 | val typeClassInstance = U.TC 8 | } 9 | } 10 | 11 | trait CoflatMapSyntax extends CoflatMap.ToCoflatMapOps with CoflatMapSyntax1 12 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/comonad.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | private[syntax] trait ComonadSyntax1 { 5 | implicit def catsSyntaxUComonad[FA](fa: FA)(implicit U: Unapply[Comonad, FA]): Comonad.Ops[U.M, U.A] = 6 | new Comonad.Ops[U.M, U.A] { 7 | val self = U.subst(fa) 8 | val typeClassInstance = U.TC 9 | } 10 | } 11 | 12 | trait ComonadSyntax extends Comonad.ToComonadOps with ComonadSyntax1 13 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/compose.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | import cats.arrow.Compose 5 | 6 | trait ComposeSyntax extends Compose.ToComposeOps 7 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/contravariant.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | import cats.functor.Contravariant 5 | 6 | private[syntax] trait ContravariantSyntax1 { 7 | implicit def catsSyntaxUContravariant[FA](fa: FA)(implicit U: Unapply[Contravariant, FA]): Contravariant.Ops[U.M, U.A] = 8 | new Contravariant.Ops[U.M, U.A] { 9 | val self = U.subst(fa) 10 | val typeClassInstance = U.TC 11 | } 12 | } 13 | 14 | trait ContravariantSyntax extends Contravariant.ToContravariantOps with ContravariantSyntax1 15 | 16 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/coproduct.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | import cats.data.Coproduct 5 | 6 | trait CoproductSyntax { 7 | implicit def catsSyntaxCoproduct[F[_], A](a: F[A]): CoproductOps[F, A] = new CoproductOps(a) 8 | } 9 | 10 | final class CoproductOps[F[_], A](val fa: F[A]) extends AnyVal { 11 | 12 | /** 13 | * Lift an `F[A]` into a `Coproduct[F, G, A]` for any type constructor `G[_]`. 14 | * 15 | * @see [[rightc]] to swap the order of `F` and `G` in the result type. 16 | * 17 | * Example: 18 | * {{{ 19 | * scala> import cats.data.Coproduct 20 | * scala> import cats.Eval 21 | * scala> import cats.implicits._ 22 | * scala> List(1, 2, 3).leftc[Eval] 23 | * res0: Coproduct[List, Eval, Int] = Coproduct(Left(List(1, 2, 3))) 24 | * }}} 25 | */ 26 | def leftc[G[_]]: Coproduct[F, G, A] = Coproduct.leftc(fa) 27 | 28 | /** 29 | * Lift an `F[A]` into a `Coproduct[G, F, A]` for any type constructor `G[_]`. 30 | * 31 | * @see [[leftc]] to swap the order of `F` and `G` in the result type. 32 | * 33 | * Example: 34 | * {{{ 35 | * scala> import cats.data.Coproduct 36 | * scala> import cats.Eval 37 | * scala> import cats.implicits._ 38 | * scala> List(1, 2, 3).rightc[Eval] 39 | * res0: Coproduct[Eval, List, Int] = Coproduct(Right(List(1, 2, 3))) 40 | * }}} 41 | */ 42 | def rightc[G[_]]: Coproduct[G, F, A] = Coproduct.rightc(fa) 43 | } 44 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/eq.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | import cats.macros.Ops 5 | 6 | trait EqSyntax { 7 | implicit def catsSyntaxEq[A: Eq](a: A): EqOps[A] = 8 | new EqOps[A](a) 9 | } 10 | 11 | final class EqOps[A: Eq](lhs: A) { 12 | def ===(rhs: A): Boolean = macro Ops.binop[A, Boolean] 13 | def =!=(rhs: A): Boolean = macro Ops.binop[A, Boolean] 14 | } 15 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/foldable.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | private[syntax] trait FoldableSyntax1 { 5 | implicit def catsSyntaxUFoldable[FA](fa: FA)(implicit U: Unapply[Foldable, FA]): Foldable.Ops[U.M, U.A] = 6 | new Foldable.Ops[U.M, U.A] { 7 | val self = U.subst(fa) 8 | val typeClassInstance = U.TC 9 | } 10 | } 11 | 12 | trait FoldableSyntax extends Foldable.ToFoldableOps with FoldableSyntax1 { 13 | implicit def catsSyntaxNestedFoldable[F[_]: Foldable, G[_], A](fga: F[G[A]]): NestedFoldableOps[F, G, A] = 14 | new NestedFoldableOps[F, G, A](fga) 15 | } 16 | 17 | final class NestedFoldableOps[F[_], G[_], A](fga: F[G[A]])(implicit F: Foldable[F]) { 18 | def sequence_(implicit G: Applicative[G]): G[Unit] = F.sequence_(fga) 19 | 20 | /** 21 | * @see [[Foldable.foldK]]. 22 | * 23 | * Example: 24 | * {{{ 25 | * scala> import cats.implicits._ 26 | * 27 | * scala> val l: List[Set[Int]] = List(Set(1, 2), Set(2, 3), Set(3, 4)) 28 | * scala> l.foldK 29 | * res0: Set[Int] = Set(1, 2, 3, 4) 30 | * }}} 31 | */ 32 | def foldK(implicit G: MonoidK[G]): G[A] = F.foldK(fga) 33 | } 34 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/functor.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | private[syntax] trait FunctorSyntax1 { 5 | implicit def catsSyntaxUFunctor[FA](fa: FA)(implicit U: Unapply[Functor, FA]): Functor.Ops[U.M, U.A] = 6 | new Functor.Ops[U.M, U.A]{ 7 | val self = U.subst(fa) 8 | val typeClassInstance = U.TC 9 | } 10 | } 11 | 12 | trait FunctorSyntax extends Functor.ToFunctorOps with FunctorSyntax1 13 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/functorFilter.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | private[syntax] trait FunctorFilterSyntax1 { 5 | implicit def catsSyntaxUFunctorFilter[FA](fa: FA)(implicit U: Unapply[FunctorFilter, FA]): FunctorFilter.Ops[U.M, U.A] = 6 | new FunctorFilter.Ops[U.M, U.A]{ 7 | val self = U.subst(fa) 8 | val typeClassInstance = U.TC 9 | } 10 | } 11 | 12 | trait FunctorFilterSyntax extends FunctorFilter.ToFunctorFilterOps with FunctorFilterSyntax1 13 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/group.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | import cats.macros.Ops 5 | 6 | trait GroupSyntax extends SemigroupSyntax { 7 | // TODO: use simulacrum instances eventually 8 | implicit def catsSyntaxGroup[A: Group](a: A): GroupOps[A] = 9 | new GroupOps[A](a) 10 | } 11 | 12 | final class GroupOps[A: Group](lhs: A) { 13 | def |-|(rhs: A): A = macro Ops.binop[A, A] 14 | def remove(rhs: A): A = macro Ops.binop[A, A] 15 | def inverse(): A = macro Ops.unop[A] 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/invariant.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | import cats.functor.Invariant 5 | 6 | private[syntax] trait InvariantSyntax1 { 7 | implicit def catsSyntaxUInvariant[FA](fa: FA)(implicit U: Unapply[Invariant, FA]): Invariant.Ops[U.M, U.A] = 8 | new Invariant.Ops[U.M, U.A] { 9 | val self = U.subst(fa) 10 | val typeClassInstance = U.TC 11 | } 12 | } 13 | 14 | trait InvariantSyntax extends Invariant.ToInvariantOps with InvariantSyntax1 15 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/list.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | import cats.data.NonEmptyList 5 | 6 | trait ListSyntax { 7 | implicit def catsSyntaxList[A](la: List[A]): ListOps[A] = new ListOps(la) 8 | } 9 | 10 | final class ListOps[A](val la: List[A]) extends AnyVal { 11 | def toNel: Option[NonEmptyList[A]] = NonEmptyList.fromList(la) 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/monadCombine.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | trait MonadCombineSyntax { 5 | // TODO: use simulacrum instances eventually 6 | implicit def catsSyntaxMonadCombine[F[_]: MonadCombine, G[_], A](fga: F[G[A]]): MonadCombineOps[F, G, A] = 7 | new MonadCombineOps[F, G, A](fga) 8 | 9 | implicit def catsSyntaxMonadCombineSeparate[F[_]: MonadCombine, G[_, _], A, B](fgab: F[G[A, B]]): SeparateOps[F, G, A, B] = 10 | new SeparateOps[F, G, A, B](fgab) 11 | } 12 | 13 | final class MonadCombineOps[F[_], G[_], A](fga: F[G[A]])(implicit F: MonadCombine[F]) { 14 | 15 | /** 16 | * @see [[MonadCombine.unite]] 17 | * 18 | * Example: 19 | * {{{ 20 | * scala> import cats.implicits._ 21 | * scala> val x: List[Vector[Int]] = List(Vector(1, 2), Vector(3, 4)) 22 | * scala> x.unite 23 | * res0: List[Int] = List(1, 2, 3, 4) 24 | * }}} 25 | */ 26 | def unite(implicit G: Foldable[G]): F[A] = F.unite(fga) 27 | } 28 | 29 | final class SeparateOps[F[_], G[_, _], A, B](fgab: F[G[A, B]])(implicit F: MonadCombine[F]) { 30 | 31 | /** 32 | * @see [[MonadCombine.separate]] 33 | * 34 | * Example: 35 | * {{{ 36 | * scala> import cats.implicits._ 37 | * scala> val l: List[Either[String, Int]] = List(Right(1), Left("error")) 38 | * scala> l.separate 39 | * res0: (List[String], List[Int]) = (List(error),List(1)) 40 | * }}} 41 | */ 42 | def separate(implicit G: Bifoldable[G]): (F[A], F[B]) = F.separate(fgab) 43 | } 44 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/monadError.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | trait MonadErrorSyntax { 5 | implicit def catsSyntaxMonadError[F[_], E, A](fa: F[A])(implicit F: MonadError[F, E]): MonadErrorOps[F, E, A] = 6 | new MonadErrorOps(fa) 7 | } 8 | 9 | final class MonadErrorOps[F[_], E, A](fa: F[A])(implicit F: MonadError[F, E]) { 10 | def ensure(error: => E)(predicate: A => Boolean): F[A] = 11 | F.ensure(fa)(error)(predicate) 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/monadFilter.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | private[syntax] trait MonadFilterSyntax1 { 5 | implicit def catsSyntaxUMonadFilter[FA](fa: FA)(implicit U: Unapply[MonadFilter, FA]): MonadFilter.Ops[U.M, U.A] = 6 | new MonadFilter.Ops[U.M, U.A] { 7 | val self = U.subst(fa) 8 | val typeClassInstance = U.TC 9 | } 10 | } 11 | 12 | trait MonadFilterSyntax extends MonadFilter.ToMonadFilterOps with MonadFilterSyntax1 13 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/monoid.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | trait MonoidSyntax extends SemigroupSyntax { 5 | // TODO: use simulacrum instances eventually 6 | implicit def catsSyntaxMonoid[A: Monoid](a: A): MonoidOps[A] = 7 | new MonoidOps[A](a) 8 | } 9 | 10 | final class MonoidOps[A: Monoid](lhs: A) { 11 | def isEmpty(implicit eq: Eq[A]): Boolean = Monoid[A].isEmpty(lhs)(eq) 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/order.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | import cats.macros.Ops 5 | import cats.kernel.Comparison 6 | 7 | trait OrderSyntax extends PartialOrderSyntax { 8 | implicit def catsSyntaxOrder[A: Order](a: A): OrderOps[A] = 9 | new OrderOps[A](a) 10 | } 11 | 12 | final class OrderOps[A: Order](lhs: A) { 13 | def compare(rhs: A): Int = macro Ops.binop[A, Int] 14 | def min(rhs: A): A = macro Ops.binop[A, A] 15 | def max(rhs: A): A = macro Ops.binop[A, A] 16 | def comparison(rhs: A): Comparison = macro Ops.binop[A, Comparison] 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/partialOrder.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | import cats.macros.Ops 5 | 6 | trait PartialOrderSyntax extends EqSyntax { 7 | implicit def catsSyntaxPartialOrder[A: PartialOrder](a: A): PartialOrderOps[A] = 8 | new PartialOrderOps[A](a) 9 | } 10 | 11 | final class PartialOrderOps[A](lhs: A)(implicit A: PartialOrder[A]) { 12 | def >(rhs: A): Boolean = macro Ops.binop[A, Boolean] 13 | def >=(rhs: A): Boolean = macro Ops.binop[A, Boolean] 14 | def <(rhs: A): Boolean = macro Ops.binop[A, Boolean] 15 | def <=(rhs: A): Boolean = macro Ops.binop[A, Boolean] 16 | 17 | def partialCompare(rhs: A): Double = macro Ops.binop[A, Double] 18 | def tryCompare(rhs: A): Option[Int] = macro Ops.binop[A, Option[Int]] 19 | def pmin(rhs: A): Option[A] = macro Ops.binop[A, Option[A]] 20 | def pmax(rhs: A): Option[A] = macro Ops.binop[A, Option[A]] 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/profunctor.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | import cats.functor.Profunctor 5 | 6 | trait ProfunctorSyntax extends Profunctor.ToProfunctorOps 7 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/reducible.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | private[syntax] trait ReducibleSyntax1 { 5 | implicit def catsSyntaxUReducible[FA](fa: FA)(implicit U: Unapply[Reducible, FA]): Reducible.Ops[U.M, U.A] = 6 | new Reducible.Ops[U.M, U.A] { 7 | val self = U.subst(fa) 8 | val typeClassInstance = U.TC 9 | } 10 | } 11 | 12 | trait ReducibleSyntax extends Reducible.ToReducibleOps with ReducibleSyntax1 { 13 | implicit def catsSyntaxNestedReducible[F[_]: Reducible, G[_], A](fga: F[G[A]]): NestedReducibleOps[F, G, A] = 14 | new NestedReducibleOps[F, G, A](fga) 15 | } 16 | 17 | final class NestedReducibleOps[F[_], G[_], A](fga: F[G[A]])(implicit F: Reducible[F]) { 18 | def reduceK(implicit G: SemigroupK[G]): G[A] = F.reduceK(fga) 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/semigroup.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | import cats.macros.Ops 5 | 6 | trait SemigroupSyntax { 7 | // TODO: use simulacrum instances eventually 8 | implicit def catsSyntaxSemigroup[A: Semigroup](a: A): SemigroupOps[A] = 9 | new SemigroupOps[A](a) 10 | } 11 | 12 | final class SemigroupOps[A: Semigroup](lhs: A) { 13 | def |+|(rhs: A): A = macro Ops.binop[A, A] 14 | def combine(rhs: A): A = macro Ops.binop[A, A] 15 | def combineN(rhs: Int): A = macro Ops.binop[A, A] 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/semigroupk.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | private[syntax] trait SemigroupKSyntax1 { 5 | // TODO: use simulacrum instances eventually 6 | implicit def catsSyntaxUSemigroup[FA](fa: FA)(implicit U: Unapply[SemigroupK, FA]): SemigroupK.Ops[U.M, U.A] = 7 | new SemigroupK.Ops[U.M, U.A] { 8 | val self = U.subst(fa) 9 | val typeClassInstance = U.TC 10 | } 11 | } 12 | 13 | trait SemigroupKSyntax extends SemigroupK.ToSemigroupKOps with SemigroupKSyntax1 14 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/split.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | import cats.arrow.Split 5 | 6 | trait SplitSyntax extends Split.ToSplitOps 7 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/strong.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | import cats.functor.Strong 5 | 6 | trait StrongSyntax extends Strong.ToStrongOps 7 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/transLift.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | trait TransLiftSyntax { 5 | implicit def catsSyntaxTransLift[E](ma: E)(implicit U: Unapply[Trivial.PH1, E]): TransLiftOps[U.M, U.A] = new TransLiftOps(U.subst(ma)) 6 | } 7 | 8 | final class TransLiftOps[M0[_], A](val ma: M0[A]) extends AnyVal { 9 | import TLExtract._ 10 | 11 | def liftT[MT0[_[_], _]](implicit extract: TLExtract[SingletonMT { type MT[F[_], B] = MT0[F, B] }, SingletonM { type M[B] = M0[B] }]): MT0[M0, A] = extract.TL.liftT(ma)(extract.TC) 12 | } 13 | 14 | trait TLExtract[MTS <: TLExtract.SingletonMT, MS <: TLExtract.SingletonM] { 15 | val TL: TransLift[MTS#MT] 16 | val TC: TL.TC[MS#M] 17 | } 18 | 19 | object TLExtract { 20 | 21 | trait SingletonMT { 22 | type MT[F[_], A] 23 | } 24 | 25 | trait SingletonM { 26 | type M[A] 27 | } 28 | 29 | implicit def extract[MTS <: SingletonMT, MS <: SingletonM, TC[_[_]]](implicit TL0: TransLift.Aux[MTS#MT, TC], TC0: TC[MS#M]): TLExtract[MTS, MS] = new TLExtract[MTS, MS] { 30 | val TL = TL0 31 | val TC = TC0 32 | } 33 | 34 | implicit def extractId[MTS <: SingletonMT, MS <: SingletonM](implicit TL0: TransLift.Aux[MTS#MT, Trivial.PH1]): TLExtract[MTS, MS] = extract[MTS, MS, Trivial.PH1] 35 | } 36 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/traverse.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | private[syntax] trait TraverseSyntax1 { 5 | implicit def catsSyntaxUTraverse[FA](fa: FA)(implicit U: Unapply[Traverse, FA]): Traverse.Ops[U.M, U.A] = 6 | new Traverse.Ops[U.M, U.A]{ 7 | val self = U.subst(fa) 8 | val typeClassInstance = U.TC 9 | } 10 | } 11 | 12 | trait TraverseSyntax extends Traverse.ToTraverseOps with TraverseSyntax1 13 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/traverseFilter.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | trait TraverseFilterSyntax extends TraverseFilter.ToTraverseFilterOps with TraverseFilterSyntax1 5 | 6 | private[syntax] trait TraverseFilterSyntax1 { 7 | implicit def catsSyntaxUTraverseFilter[FA](fa: FA)(implicit U: Unapply[TraverseFilter, FA]): TraverseFilter.Ops[U.M, U.A] = 8 | new TraverseFilter.Ops[U.M, U.A]{ 9 | val self = U.subst(fa) 10 | val typeClassInstance = U.TC 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/tuple.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | trait TupleSyntax extends TupleCartesianSyntax 5 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/validated.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | import cats.data.{ Validated, ValidatedNel } 5 | 6 | trait ValidatedSyntax { 7 | implicit def catsSyntaxValidatedId[A](a: A): ValidatedIdSyntax[A] = new ValidatedIdSyntax(a) 8 | } 9 | 10 | final class ValidatedIdSyntax[A](val a: A) extends AnyVal { 11 | def valid[B]: Validated[B, A] = Validated.Valid(a) 12 | def validNel[B]: ValidatedNel[B, A] = Validated.Valid(a) 13 | def invalid[B]: Validated[A, B] = Validated.Invalid(a) 14 | def invalidNel[B]: ValidatedNel[A, B] = Validated.invalidNel(a) 15 | } 16 | -------------------------------------------------------------------------------- /core/src/main/scala/cats/syntax/writer.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package syntax 3 | 4 | import cats.data.Writer 5 | 6 | trait WriterSyntax { 7 | implicit def catsSyntaxWriterId[A](a: A): WriterIdSyntax[A] = new WriterIdSyntax(a) 8 | } 9 | 10 | final class WriterIdSyntax[A](val a: A) extends AnyVal { 11 | def tell: Writer[A, Unit] = Writer(a, ()) 12 | def writer[W](w: W): Writer[W, A] = Writer(w, a) 13 | } 14 | -------------------------------------------------------------------------------- /docs/src/main/tut/applicative.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: "Applicative" 4 | section: "typeclasses" 5 | source: "core/src/main/scala/cats/Applicative.scala" 6 | scaladoc: "#cats.Applicative" 7 | --- 8 | # Applicative 9 | 10 | `Applicative` extends [`Apply`](apply.html) by adding a single method, 11 | `pure`: 12 | 13 | ```scala 14 | def pure[A](x: A): F[A] 15 | ```` 16 | 17 | This method takes any value and returns the value in the context of 18 | the functor. For many familiar functors, how to do this is 19 | obvious. For `Option`, the `pure` operation wraps the value in 20 | `Some`. For `List`, the `pure` operation returns a single element 21 | `List`: 22 | 23 | ```tut:book 24 | import cats._ 25 | import cats.implicits._ 26 | 27 | Applicative[Option].pure(1) 28 | Applicative[List].pure(1) 29 | ``` 30 | 31 | Like [`Functor`](functor.html) and [`Apply`](apply.html), `Applicative` 32 | functors also compose naturally with each other. When 33 | you compose one `Applicative` with another, the resulting `pure` 34 | operation will lift the passed value into one context, and the result 35 | into the other context: 36 | 37 | ```tut:book 38 | import cats.data.Nested 39 | val nested = Applicative[Nested[List, Option, ?]].pure(1) 40 | val unwrapped = nested.value 41 | ``` 42 | 43 | ## Applicative Functors & Monads 44 | 45 | `Applicative` is a generalization of [`Monad`](monad.html), allowing expression 46 | of effectful computations in a pure functional way. 47 | 48 | `Applicative` is generally preferred to `Monad` when the structure of a 49 | computation is fixed a priori. That makes it possible to perform certain 50 | kinds of static analysis on applicative values. 51 | -------------------------------------------------------------------------------- /docs/src/main/tut/monadcombine.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: "MonadCombine" 4 | section: "typeclasses" 5 | source: "core/src/main/scala/cats/MonadCombine.scala" 6 | scaladoc: "#cats.MonadCombine" 7 | --- 8 | # MonadCombine 9 | 10 | -------------------------------------------------------------------------------- /docs/src/main/tut/monadfilter.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: "MonadFilter" 4 | section: "typeclasses" 5 | source: "core/src/main/scala/cats/MonadFilter.scala" 6 | scaladoc: "#cats.MonadFilter" 7 | --- 8 | # MonadFilter 9 | 10 | -------------------------------------------------------------------------------- /docs/src/main/tut/monoidk.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: "MonoidK" 4 | section: "typeclasses" 5 | source: "core/src/main/scala/cats/MonoidK.scala" 6 | scaladoc: "#cats.MonoidK" 7 | --- 8 | # MonoidK 9 | 10 | `MonoidK` is a universal monoid which operates on kinds. 11 | 12 | This type class is useful when its type parameter `F[_]` has a 13 | structure that can be combined for any particular type, and which 14 | also has an "empty" representation. Thus, `MonoidK` is like a `Monoid` 15 | for kinds (i.e. parameterized types). 16 | 17 | A `MonoidK[F]` can produce a `Monoid[F[A]]` for any type `A`. 18 | 19 | Here's how to distinguish `Monoid` and `MonoidK`: 20 | 21 | - `Monoid[A]` allows `A` values to be combined, and also means there 22 | is an "empty" A value that functions as an identity. 23 | 24 | - `MonoidK[F]` allows two `F[A]` values to be combined, for any `A`. It 25 | also means that for any `A`, there is an "empty" `F[A]` value. The 26 | combination operation and empty value just depend on the 27 | structure of `F`, but not on the structure of `A`. 28 | -------------------------------------------------------------------------------- /docs/src/main/tut/oneand.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: "OneAnd" 4 | section: "data" 5 | source: "core/src/main/scala/cats/data/OneAnd.scala" 6 | scaladoc: "#cats.data.OneAnd" 7 | --- 8 | # OneAnd 9 | 10 | The `OneAnd[F[_],A]` data type represents a single element of type `A` 11 | that is guaranteed to be present (`head`) and in addition to this a 12 | second part that is wrapped inside an higher kinded type constructor 13 | `F[_]`. By choosing the `F` parameter, you can model for example 14 | non-empty lists by choosing `List` for `F`, giving: 15 | 16 | ```tut:silent 17 | import cats.data.OneAnd 18 | 19 | type NonEmptyList[A] = OneAnd[List, A] 20 | ``` 21 | 22 | which is the actual implementation of non-empty lists in cats. By 23 | having the higher kinded type parameter `F[_]`, `OneAnd` is also able 24 | to represent other "non-empty" data structures e.g. 25 | 26 | ```tut:silent 27 | import cats.data.OneAnd 28 | 29 | type NonEmptyStream[A] = OneAnd[Stream, A] 30 | ``` -------------------------------------------------------------------------------- /docs/src/main/tut/show.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: "Show" 4 | section: "typeclasses" 5 | source: "core/src/main/scala/cats/Show.scala" 6 | scaladoc: "#cats.Show" 7 | --- 8 | # Show 9 | 10 | -------------------------------------------------------------------------------- /docs/src/site/_config.yml: -------------------------------------------------------------------------------- 1 | name: Cats Documentation 2 | markdown: kramdown 3 | highlighter: rouge 4 | # this kramdown config is for local use and I think GitHub's Jekyll ignores it 5 | kramdown: 6 | input: GFM 7 | syntax_highlighter: rouge 8 | baseurl: /cats 9 | apidocs: /cats/api/ 10 | sources: https://github.com/typelevel/cats/blob/master/ 11 | 12 | collections: 13 | tut: 14 | output: true 15 | -------------------------------------------------------------------------------- /docs/src/site/bin/local-server: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | 5 | jekyll serve --config "$DIR/../_config.dev.yml" --watch 6 | -------------------------------------------------------------------------------- /docs/src/site/colophon.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: "Colophon" 4 | section: "colophon" 5 | --- 6 | Cats has been made a much better project, and is a much more enjoyable 7 | project to work on because of many of the other projects on which Cats 8 | is built. Many of these projects have had enhancements made in order 9 | to benefit Cats, for which we are grateful. 10 | 11 | We would like to thank the maintainers of these supporting projects, 12 | and we'd encourage you to check out these projects and consider 13 | integrating them into your own projects. 14 | 15 | * [simulacrum](https://github.com/mpilquist/simulacrum) for minimizing type class boilerplate 16 | * [machinist](https://github.com/typelevel/machinist) for optimizing implicit operators 17 | * [scalacheck](http://scalacheck.org) for property-based testing 18 | * [discipline](https://github.com/typelevel/discipline) for encoding and testing laws 19 | * [kind-projector](https://github.com/non/kind-projector) for type lambda syntax 20 | * [tut](https://github.com/tpolecat/tut) type-checked example code makes sure that our examples stay in sync with the rest of our source 21 | 22 | There are other libraries that aim to foster Functional Programming in the Scala programming language which Cats has a relationship to: 23 | 24 | * [scalaz](https://github.com/scalaz/scalaz) The project which directly inspires Cats. Currently Cats borrows some code directly from scalaz. 25 | * [Structures](https://github.com/mpilquist/Structures) A project very similar in 26 | nature to Cats, also derived from scalaz. The Structures and Cats 27 | projects have had a healthy relationship of sharing both ideas and code. 28 | 29 | -------------------------------------------------------------------------------- /docs/src/site/datatypes.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: "Data Types" 4 | section: "data" 5 | --- 6 | # Data Types 7 | 8 | {% for x in site.tut %} 9 | {% if x.section == 'data' %} 10 | - [{{x.title}}]({{site.baseurl}}{{x.url}}) 11 | {% endif %} 12 | {% endfor %} 13 | -------------------------------------------------------------------------------- /docs/src/site/js/scale.fix.js: -------------------------------------------------------------------------------- 1 | var metas = document.getElementsByTagName('meta'); 2 | var i; 3 | if (navigator.userAgent.match(/iPhone/i)) { 4 | for (i=0; i Trampoline[A]): Trampoline[A] = 11 | Free.suspend(a) 12 | 13 | def delay[A](a: => A): Trampoline[A] = 14 | suspend(done(a)) 15 | } 16 | 17 | -------------------------------------------------------------------------------- /free/src/main/scala/cats/free/Yoneda.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package free 3 | 4 | /** 5 | * The free functor generated by `F`. The Yoneda lemma says that 6 | * `Yoneda[F,A]` is isomorphic to `F[A]` for any functor `F`. 7 | * The homomorphism from `Yoneda[F,A]` to `F[A]` exists even when 8 | * we have forgotten that `F` is a functor. 9 | * Can be seen as a partially applied `map` for the functor `F`. 10 | */ 11 | abstract class Yoneda[F[_], A] extends Serializable { self => 12 | def apply[B](f: A => B): F[B] 13 | 14 | /** 15 | * Converts to `F[A]` even without a `Functor` instance for `F`. 16 | */ 17 | def run: F[A] = apply(a => a) 18 | 19 | /** 20 | * Converts to `Coyoneda[F,A]` even without a `Functor` instance for `F`. 21 | */ 22 | def toCoyoneda: Coyoneda.Aux[F, A, A] = Coyoneda(run)(identity[A]) 23 | 24 | /** 25 | * Simple function composition. Allows map fusion without traversing an `F`. 26 | */ 27 | def map[B](f: A => B): Yoneda[F, B] = 28 | new Yoneda[F, B] { 29 | def apply[C](g: B => C): F[C] = self(f andThen g) 30 | } 31 | } 32 | 33 | object Yoneda { 34 | 35 | /** 36 | * `Yoneda[F, _]` is a functor for any `F`. 37 | */ 38 | implicit def catsFreeFunctorForYoneda[F[_]]: Functor[Yoneda[F, ?]] = 39 | new Functor[Yoneda[F, ?]] { 40 | def map[A, B](ya: Yoneda[F, A])(f: A => B): Yoneda[F, B] = ya map f 41 | } 42 | 43 | /** 44 | * `F[A]` converts to `Yoneda[F, A]` for any functor `F`. 45 | */ 46 | def apply[F[_], A](fa: F[A])(implicit F: Functor[F]): Yoneda[F, A] = 47 | new Yoneda[F, A] { 48 | def apply[B](f: A => B): F[B] = F.map(fa)(f) 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /free/src/main/scala/cats/free/package.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | package object free { 4 | /** Alias for the free monad over the `Function0` functor. */ 5 | type Trampoline[A] = Free[Function0, A] 6 | object Trampoline extends TrampolineFunctions 7 | 8 | /** [[cats.free.Inject]][F, G] */ 9 | type :<:[F[_], G[_]] = Inject[F, G] 10 | 11 | /** [[cats.free.Inject]][F, G] */ 12 | type :≺:[F[_], G[_]] = Inject[F, G] 13 | 14 | } 15 | -------------------------------------------------------------------------------- /free/src/test/scala/cats/free/CoyonedaTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package free 3 | 4 | import cats.tests.CatsSuite 5 | import cats.arrow.FunctionK 6 | import cats.laws.discipline.{FunctorTests, SerializableTests} 7 | 8 | import org.scalacheck.Arbitrary 9 | 10 | class CoyonedaTests extends CatsSuite { 11 | implicit def coyonedaArbitrary[F[_] : Functor, A : Arbitrary](implicit F: Arbitrary[F[A]]): Arbitrary[Coyoneda[F, A]] = 12 | Arbitrary(F.arbitrary.map(Coyoneda.lift)) 13 | 14 | implicit def coyonedaEq[F[_]: Functor, A](implicit FA: Eq[F[A]]): Eq[Coyoneda[F, A]] = 15 | new Eq[Coyoneda[F, A]] { 16 | def eqv(a: Coyoneda[F, A], b: Coyoneda[F, A]): Boolean = FA.eqv(a.run, b.run) 17 | } 18 | 19 | checkAll("Coyoneda[Option, ?]", FunctorTests[Coyoneda[Option, ?]].functor[Int, Int, Int]) 20 | checkAll("Functor[Coyoneda[Option, ?]]", SerializableTests.serializable(Functor[Coyoneda[Option, ?]])) 21 | 22 | test("toYoneda and then toCoyoneda is identity"){ 23 | forAll{ (y: Coyoneda[Option, Int]) => 24 | y.toYoneda.toCoyoneda should === (y) 25 | } 26 | } 27 | 28 | test("transform and run is same as applying natural trans") { 29 | val nt = 30 | new FunctionK[Option, List] { 31 | def apply[A](fa: Option[A]): List[A] = fa.toList 32 | } 33 | val o = Option("hello") 34 | val c = Coyoneda.lift(o) 35 | c.transform(nt).run should === (nt(o)) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /free/src/test/scala/cats/free/YonedaTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package free 3 | 4 | import cats.tests.CatsSuite 5 | import cats.laws.discipline.{FunctorTests, SerializableTests} 6 | 7 | import org.scalacheck.Arbitrary 8 | 9 | class YonedaTests extends CatsSuite { 10 | implicit def yonedaArbitrary[F[_] : Functor, A](implicit F: Arbitrary[F[A]]): Arbitrary[Yoneda[F, A]] = 11 | Arbitrary(F.arbitrary.map(Yoneda(_))) 12 | 13 | implicit def yonedaEq[F[_]: Functor, A](implicit FA: Eq[F[A]]): Eq[Yoneda[F, A]] = 14 | new Eq[Yoneda[F, A]] { 15 | def eqv(a: Yoneda[F, A], b: Yoneda[F, A]): Boolean = FA.eqv(a.run, b.run) 16 | } 17 | 18 | checkAll("Yoneda[Option, ?]", FunctorTests[Yoneda[Option, ?]].functor[Int, Int, Int]) 19 | checkAll("Functor[Yoneda[Option, ?]]", SerializableTests.serializable(Functor[Yoneda[Option, ?]])) 20 | 21 | test("toCoyoneda and then toYoneda is identity"){ 22 | forAll{ (y: Yoneda[Option, Int]) => 23 | y.toCoyoneda.toYoneda should === (y) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /jvm/src/test/scala/cats/tests/FutureTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package jvm 3 | package tests 4 | 5 | import cats.laws.discipline._ 6 | import cats.tests.CatsSuite 7 | 8 | import scala.concurrent.{Await, Future} 9 | import scala.concurrent.duration._ 10 | import scala.concurrent.ExecutionContext.Implicits.global 11 | 12 | import org.scalacheck.Arbitrary 13 | import org.scalacheck.Arbitrary.arbitrary 14 | 15 | class FutureTests extends CatsSuite { 16 | val timeout = 3.seconds 17 | 18 | def futureEither[A](f: Future[A]): Future[Either[Throwable, A]] = 19 | f.map(Either.right[Throwable, A]).recover { case t => Either.left(t) } 20 | 21 | implicit def eqfa[A: Eq]: Eq[Future[A]] = 22 | new Eq[Future[A]] { 23 | def eqv(fx: Future[A], fy: Future[A]): Boolean = { 24 | val fz = futureEither(fx) zip futureEither(fy) 25 | Await.result(fz.map { case (tx, ty) => tx === ty }, timeout) 26 | } 27 | } 28 | 29 | implicit val throwableEq: Eq[Throwable] = 30 | Eq.fromUniversalEquals 31 | 32 | // Need non-fatal Throwables for Future recoverWith/handleError 33 | implicit val nonFatalArbitrary: Arbitrary[Throwable] = 34 | Arbitrary(arbitrary[Exception].map(identity)) 35 | 36 | checkAll("Future with Throwable", MonadErrorTests[Future, Throwable].monadError[Int, Int, Int]) 37 | checkAll("Future", MonadTests[Future].monad[Int, Int, Int]) 38 | } 39 | -------------------------------------------------------------------------------- /kernel-laws/src/main/scala/cats/kernel/laws/BaseLaws.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel.laws 2 | 3 | import cats.kernel._ 4 | 5 | import org.typelevel.discipline.Laws 6 | 7 | import org.scalacheck.{Arbitrary, Prop} 8 | 9 | object BaseLaws { 10 | def apply[A : Eq : Arbitrary]: BaseLaws[A] = new BaseLaws[A] { 11 | def Equ = Eq[A] 12 | def Arb = implicitly[Arbitrary[A]] 13 | } 14 | } 15 | 16 | trait BaseLaws[A] extends Laws { 17 | 18 | implicit def Equ: Eq[A] 19 | implicit def Arb: Arbitrary[A] 20 | 21 | class BaseRuleSet( 22 | val name: String, 23 | val parent: Option[RuleSet], 24 | val bases: Seq[(String, Laws#RuleSet)], 25 | val props: (String, Prop)* 26 | ) extends RuleSet with HasOneParent 27 | } 28 | -------------------------------------------------------------------------------- /kernel-laws/src/main/scala/cats/kernel/laws/IsSerializable.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel.laws 2 | 3 | import catalysts.Platform 4 | import org.scalacheck.Prop 5 | import org.scalacheck.Prop._ 6 | import scala.util.control.NonFatal 7 | import scala.util.DynamicVariable 8 | 9 | /** 10 | * Object with a dynamic variable that allows users to skip the 11 | * serialization tests for certain instances. 12 | */ 13 | private[laws] object IsSerializable { 14 | val runTests = new DynamicVariable[Boolean](true) 15 | def apply(): Boolean = (!Platform.isJs) && runTests.value 16 | 17 | def testSerialization[M](m: M): Prop.Result = 18 | if (Platform.isJs) Result(status = Proof) else { 19 | import java.io._ 20 | val baos = new ByteArrayOutputStream() 21 | val oos = new ObjectOutputStream(baos) 22 | var ois: ObjectInputStream = null // scalastyle:ignore null 23 | try { 24 | oos.writeObject(m) 25 | oos.close() 26 | val bais = new ByteArrayInputStream(baos.toByteArray()) 27 | ois = new ObjectInputStream(bais) 28 | val m2 = ois.readObject() // just ensure we can read it back 29 | ois.close() 30 | Result(status = Proof) 31 | } catch { case NonFatal(t) => 32 | Result(status = Exception(t)) 33 | } finally { 34 | oos.close() 35 | if (ois != null) ois.close() // scalastyle:ignore null 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /kernel-laws/src/main/scala/cats/kernel/laws/package.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | 3 | import org.scalacheck._ 4 | import org.scalacheck.util.Pretty 5 | import Prop.{False, Proof, Result} 6 | 7 | package object laws { 8 | 9 | lazy val proved = Prop(Result(status = Proof)) 10 | 11 | lazy val falsified = Prop(Result(status = False)) 12 | 13 | object Ops { 14 | def run[A](sym: String)(lhs: A, rhs: A)(f: (A, A) => Boolean): Prop = 15 | if (f(lhs, rhs)) proved else falsified :| { 16 | val exp = Pretty.pretty(lhs, Pretty.Params(0)) 17 | val got = Pretty.pretty(rhs, Pretty.Params(0)) 18 | s"($exp $sym $got) failed" 19 | } 20 | } 21 | 22 | implicit class CheckEqOps[A](lhs: A)(implicit ev: Eq[A], pp: A => Pretty) { 23 | def ?==(rhs: A): Prop = Ops.run("?==")(lhs, rhs)(ev.eqv) 24 | def ?!=(rhs: A): Prop = Ops.run("?!=")(lhs, rhs)(ev.neqv) 25 | } 26 | 27 | implicit class CheckOrderOps[A](lhs: A)(implicit ev: PartialOrder[A], pp: A => Pretty) { 28 | def ?<(rhs: A): Prop = Ops.run("?<")(lhs, rhs)(ev.lt) 29 | def ?<=(rhs: A): Prop = Ops.run("?<=")(lhs, rhs)(ev.lteqv) 30 | def ?>(rhs: A): Prop = Ops.run("?>")(lhs, rhs)(ev.gt) 31 | def ?>=(rhs: A): Prop = Ops.run("?>=")(lhs, rhs)(ev.gteqv) 32 | } 33 | 34 | implicit class BooleanOps[A](lhs: Boolean)(implicit pp: Boolean => Pretty) { 35 | def ?&&(rhs: Boolean): Prop = Ops.run("?&&")(lhs, rhs)(_ && _) 36 | def ?||(rhs: Boolean): Prop = Ops.run("?||")(lhs, rhs)(_ || _) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/Band.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | 3 | import scala.{specialized => sp} 4 | 5 | 6 | /** 7 | * Bands are semigroups whose operation 8 | * (i.e. combine) is also idempotent. 9 | */ 10 | trait Band[@sp(Int, Long, Float, Double) A] extends Any with Semigroup[A] 11 | 12 | object Band extends SemigroupFunctions[Band] { 13 | 14 | /** 15 | * Access an implicit `Band[A]`. 16 | */ 17 | @inline final def apply[@sp(Int, Long, Float, Double) A](implicit ev: Band[A]): Band[A] = ev 18 | } 19 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/BoundedSemilattice.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | 3 | import scala.{specialized => sp} 4 | 5 | trait BoundedSemilattice[@sp(Int, Long, Float, Double) A] extends Any with Semilattice[A] with CommutativeMonoid[A] 6 | 7 | object BoundedSemilattice extends SemilatticeFunctions[BoundedSemilattice] { 8 | 9 | /** 10 | * Access an implicit `BoundedSemilattice[A]`. 11 | */ 12 | @inline final def apply[@sp(Int, Long, Float, Double) A](implicit ev: BoundedSemilattice[A]): BoundedSemilattice[A] = ev 13 | } 14 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/CommutativeGroup.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | 3 | import scala.{ specialized => sp } 4 | 5 | /** 6 | * An commutative group (also known as an abelian group) is a group 7 | * whose combine operation is commutative. 8 | */ 9 | trait CommutativeGroup[@sp(Int, Long, Float, Double) A] extends Any with Group[A] with CommutativeMonoid[A] 10 | 11 | object CommutativeGroup extends GroupFunctions[CommutativeGroup] { 12 | 13 | /** 14 | * Access an implicit `CommutativeGroup[A]`. 15 | */ 16 | @inline final def apply[A](implicit ev: CommutativeGroup[A]): CommutativeGroup[A] = ev 17 | } 18 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/CommutativeMonoid.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | 3 | import scala.{ specialized => sp } 4 | 5 | /** 6 | * CommutativeMonoid represents a commutative monoid. 7 | * 8 | * A monoid is commutative if for all x and y, x |+| y === y |+| x. 9 | */ 10 | trait CommutativeMonoid[@sp(Int, Long, Float, Double) A] extends Any with Monoid[A] with CommutativeSemigroup[A] 11 | 12 | object CommutativeMonoid extends MonoidFunctions[CommutativeMonoid] { 13 | /** 14 | * Access an implicit `CommutativeMonoid[A]`. 15 | */ 16 | @inline final def apply[A](implicit ev: CommutativeMonoid[A]): CommutativeMonoid[A] = ev 17 | } 18 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/CommutativeSemigroup.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | 3 | import scala.{ specialized => sp } 4 | 5 | /** 6 | * CommutativeSemigroup represents a commutative semigroup. 7 | * 8 | * A semigroup is commutative if for all x and y, x |+| y === y |+| x. 9 | */ 10 | trait CommutativeSemigroup[@sp(Int, Long, Float, Double) A] extends Any with Semigroup[A] 11 | 12 | object CommutativeSemigroup extends SemigroupFunctions[CommutativeSemigroup] { 13 | 14 | /** 15 | * Access an implicit `CommutativeSemigroup[A]`. 16 | */ 17 | @inline final def apply[A](implicit ev: CommutativeSemigroup[A]): CommutativeSemigroup[A] = ev 18 | } 19 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/Comparison.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | 3 | /** ADT encoding the possible results of a comparison */ 4 | sealed abstract class Comparison(val toInt: Int, val toDouble: Double) extends Product with Serializable 5 | 6 | object Comparison { 7 | final case object GreaterThan extends Comparison(1, 1.0) 8 | final case object EqualTo extends Comparison(0, 0.0) 9 | final case object LessThan extends Comparison(-1, -1.0) 10 | 11 | // Used for fromDouble 12 | private val SomeGt = Some(Comparison.GreaterThan) 13 | private val SomeEq = Some(Comparison.EqualTo) 14 | private val SomeLt = Some(Comparison.LessThan) 15 | 16 | def fromInt(int: Int): Comparison = { 17 | if (int > 0) Comparison.GreaterThan 18 | else if (int == 0) Comparison.EqualTo 19 | else Comparison.LessThan 20 | } 21 | 22 | def fromDouble(double: Double): Option[Comparison] = { 23 | if (double.isNaN) None 24 | else if (double > 0.0) SomeGt 25 | else if (double == 0.0) SomeEq 26 | else SomeLt 27 | } 28 | 29 | implicit val catsKernelEqForComparison: Eq[Comparison] = Eq.fromUniversalEquals 30 | } 31 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/instances/all.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | package instances 3 | 4 | package object all extends AllInstances 5 | 6 | trait AllInstances 7 | extends BigDecimalInstances 8 | with BigIntInstances 9 | with BitSetInstances 10 | with BooleanInstances 11 | with ByteInstances 12 | with CharInstances 13 | with DoubleInstances 14 | with FloatInstances 15 | with FunctionInstances 16 | with IntInstances 17 | with ListInstances 18 | with LongInstances 19 | with MapInstances 20 | with OptionInstances 21 | with SetInstances 22 | with ShortInstances 23 | with StreamInstances 24 | with StringInstances 25 | with TupleInstances 26 | with UnitInstances 27 | with VectorInstances 28 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/instances/bigDecimal.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | package instances 3 | 4 | package object bigDecimal extends BigDecimalInstances // scalastyle:ignore package.object.name 5 | 6 | trait BigDecimalInstances { 7 | implicit val catsKernelStdOrderForBigDecimal: Order[BigDecimal] = 8 | new BigDecimalOrder 9 | implicit val catsKernelStdGroupForBigDecimal: CommutativeGroup[BigDecimal] = 10 | new BigDecimalGroup 11 | } 12 | 13 | class BigDecimalGroup extends CommutativeGroup[BigDecimal] { 14 | val empty: BigDecimal = BigDecimal(0) 15 | def combine(x: BigDecimal, y: BigDecimal): BigDecimal = x + y 16 | def inverse(x: BigDecimal): BigDecimal = -x 17 | override def remove(x: BigDecimal, y: BigDecimal): BigDecimal = x - y 18 | } 19 | 20 | class BigDecimalOrder extends Order[BigDecimal] { 21 | 22 | def compare(x: BigDecimal, y: BigDecimal): Int = x compare y 23 | 24 | override def eqv(x: BigDecimal, y: BigDecimal): Boolean = x == y 25 | override def neqv(x: BigDecimal, y: BigDecimal): Boolean = x != y 26 | override def gt(x: BigDecimal, y: BigDecimal): Boolean = x > y 27 | override def gteqv(x: BigDecimal, y: BigDecimal): Boolean = x >= y 28 | override def lt(x: BigDecimal, y: BigDecimal): Boolean = x < y 29 | override def lteqv(x: BigDecimal, y: BigDecimal): Boolean = x <= y 30 | 31 | override def min(x: BigDecimal, y: BigDecimal): BigDecimal = x min y 32 | override def max(x: BigDecimal, y: BigDecimal): BigDecimal = x max y 33 | } 34 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/instances/bigInt.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | package instances 3 | 4 | package object bigInt extends BigIntInstances // scalastyle:ignore package.object.name 5 | 6 | trait BigIntInstances { 7 | implicit val catsKernelStdOrderForBigInt: Order[BigInt] = 8 | new BigIntOrder 9 | implicit val catsKernelStdGroupForBigInt: CommutativeGroup[BigInt] = 10 | new BigIntGroup 11 | } 12 | 13 | class BigIntGroup extends CommutativeGroup[BigInt] { 14 | val empty: BigInt = BigInt(0) 15 | def combine(x: BigInt, y: BigInt): BigInt = x + y 16 | def inverse(x: BigInt): BigInt = -x 17 | override def remove(x: BigInt, y: BigInt): BigInt = x - y 18 | } 19 | 20 | class BigIntOrder extends Order[BigInt] { 21 | 22 | def compare(x: BigInt, y: BigInt): Int = x compare y 23 | 24 | override def eqv(x: BigInt, y: BigInt): Boolean = x == y 25 | override def neqv(x: BigInt, y: BigInt): Boolean = x != y 26 | override def gt(x: BigInt, y: BigInt): Boolean = x > y 27 | override def gteqv(x: BigInt, y: BigInt): Boolean = x >= y 28 | override def lt(x: BigInt, y: BigInt): Boolean = x < y 29 | override def lteqv(x: BigInt, y: BigInt): Boolean = x <= y 30 | 31 | override def min(x: BigInt, y: BigInt): BigInt = x min y 32 | override def max(x: BigInt, y: BigInt): BigInt = x max y 33 | } 34 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/instances/bitSet.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | package instances 3 | 4 | import scala.collection.immutable.BitSet 5 | 6 | package object bitSet extends BitSetInstances 7 | 8 | trait BitSetInstances { 9 | implicit val catsKernelStdPartialOrderForBitSet: PartialOrder[BitSet] = 10 | new BitSetPartialOrder 11 | 12 | implicit val catsKernelStdSemilatticeForBitSet: BoundedSemilattice[BitSet] = 13 | new BitSetSemilattice 14 | } 15 | 16 | class BitSetPartialOrder extends PartialOrder[BitSet] { 17 | def partialCompare(x: BitSet, y: BitSet): Double = 18 | if (x eq y) 0.0 19 | else if (x.size < y.size) if (x.subsetOf(y)) -1.0 else Double.NaN 20 | else if (y.size < x.size) if (y.subsetOf(x)) 1.0 else Double.NaN 21 | else if (x == y) 0.0 22 | else Double.NaN 23 | 24 | override def eqv(x: BitSet, y: BitSet): Boolean = 25 | x == y 26 | } 27 | 28 | class BitSetSemilattice extends BoundedSemilattice[BitSet] { 29 | def empty: BitSet = BitSet.empty 30 | def combine(x: BitSet, y: BitSet): BitSet = x | y 31 | } 32 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/instances/boolean.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | package instances 3 | 4 | package object boolean extends BooleanInstances 5 | 6 | trait BooleanInstances { 7 | implicit val catsKernelStdOrderForBoolean: Order[Boolean] = 8 | new BooleanOrder 9 | } 10 | 11 | class BooleanOrder extends Order[Boolean] { 12 | def compare(x: Boolean, y: Boolean): Int = 13 | if (x == y) 0 else if (x) 1 else -1 14 | 15 | override def eqv(x:Boolean, y:Boolean): Boolean = x == y 16 | override def neqv(x:Boolean, y:Boolean): Boolean = x != y 17 | override def gt(x: Boolean, y: Boolean): Boolean = x && !y 18 | override def lt(x: Boolean, y: Boolean): Boolean = !x && y 19 | override def gteqv(x: Boolean, y: Boolean): Boolean = x == y || x 20 | override def lteqv(x: Boolean, y: Boolean): Boolean = x == y || y 21 | 22 | override def min(x: Boolean, y: Boolean): Boolean = x && y 23 | override def max(x: Boolean, y: Boolean): Boolean = x || y 24 | } 25 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/instances/byte.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | package instances 3 | 4 | package object byte extends ByteInstances 5 | 6 | trait ByteInstances { 7 | implicit val catsKernelStdOrderForByte: Order[Byte] = new ByteOrder 8 | implicit val catsKernelStdGroupForByte: CommutativeGroup[Byte] = new ByteGroup 9 | } 10 | 11 | class ByteGroup extends CommutativeGroup[Byte] { 12 | def combine(x: Byte, y: Byte): Byte = (x + y).toByte 13 | def empty: Byte = 0 14 | def inverse(x: Byte): Byte = (-x).toByte 15 | override def remove(x: Byte, y: Byte): Byte = (x - y).toByte 16 | } 17 | 18 | class ByteOrder extends Order[Byte] { 19 | 20 | def compare(x: Byte, y: Byte): Int = 21 | if (x < y) -1 else if (x > y) 1 else 0 22 | 23 | override def eqv(x: Byte, y: Byte): Boolean = x == y 24 | override def neqv(x: Byte, y: Byte): Boolean = x != y 25 | override def gt(x: Byte, y: Byte): Boolean = x > y 26 | override def gteqv(x: Byte, y: Byte): Boolean = x >= y 27 | override def lt(x: Byte, y: Byte): Boolean = x < y 28 | override def lteqv(x: Byte, y: Byte): Boolean = x <= y 29 | 30 | override def min(x: Byte, y: Byte): Byte = 31 | java.lang.Math.min(x.toInt, y.toInt).toByte 32 | override def max(x: Byte, y: Byte): Byte = 33 | java.lang.Math.max(x.toInt, y.toInt).toByte 34 | } 35 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/instances/char.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | package instances 3 | 4 | package object char extends CharInstances 5 | 6 | trait CharInstances { 7 | implicit val catsKernelStdOrderForChar = new CharOrder 8 | } 9 | 10 | class CharOrder extends Order[Char] { 11 | def compare(x: Char, y: Char): Int = 12 | if (x < y) -1 else if (x > y) 1 else 0 13 | override def eqv(x:Char, y:Char): Boolean = x == y 14 | override def neqv(x:Char, y:Char): Boolean = x != y 15 | override def gt(x: Char, y: Char): Boolean = x > y 16 | override def gteqv(x: Char, y: Char): Boolean = x >= y 17 | override def lt(x: Char, y: Char): Boolean = x < y 18 | override def lteqv(x: Char, y: Char): Boolean = x <= y 19 | } 20 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/instances/double.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | package instances 3 | 4 | import java.lang.Math 5 | 6 | package object double extends DoubleInstances 7 | 8 | trait DoubleInstances { 9 | implicit val catsKernelStdOrderForDouble: Order[Double] = new DoubleOrder 10 | implicit val catsKernelStdGroupForDouble: CommutativeGroup[Double] = new DoubleGroup 11 | } 12 | 13 | class DoubleGroup extends CommutativeGroup[Double] { 14 | def combine(x: Double, y: Double): Double = x + y 15 | def empty: Double = 0D 16 | def inverse(x: Double): Double = -x 17 | override def remove(x: Double, y: Double): Double = x - y 18 | } 19 | 20 | class DoubleOrder extends Order[Double] { 21 | 22 | def compare(x: Double, y: Double): Int = 23 | java.lang.Double.compare(x, y) 24 | 25 | override def eqv(x:Double, y:Double): Boolean = x == y 26 | override def neqv(x:Double, y:Double): Boolean = x != y 27 | override def gt(x: Double, y: Double): Boolean = x > y 28 | override def gteqv(x: Double, y: Double): Boolean = x >= y 29 | override def lt(x: Double, y: Double): Boolean = x < y 30 | override def lteqv(x: Double, y: Double): Boolean = x <= y 31 | 32 | override def min(x: Double, y: Double): Double = 33 | Math.min(x, y) 34 | override def max(x: Double, y: Double): Double = 35 | Math.max(x, y) 36 | } 37 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/instances/float.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | package instances 3 | 4 | package object float extends FloatInstances 5 | 6 | trait FloatInstances { 7 | implicit val catsKernelStdOrderForFloat: Order[Float] = new FloatOrder 8 | implicit val catsKernelStdGroupForFloat: CommutativeGroup[Float] = new FloatGroup 9 | } 10 | 11 | /** 12 | * This is only approximately associative. 13 | */ 14 | class FloatGroup extends CommutativeGroup[Float] { 15 | def combine(x: Float, y: Float): Float = x + y 16 | def empty: Float = 0F 17 | def inverse(x: Float): Float = -x 18 | override def remove(x: Float, y: Float): Float = x - y 19 | } 20 | 21 | /** 22 | * Due to the way floating-point equality works, this instance is not 23 | * lawful under equality, but is correct when taken as an 24 | * approximation of an exact value. 25 | * 26 | * If you would prefer an absolutely lawful fractional value, you'll 27 | * need to investigate rational numbers or more exotic types. 28 | */ 29 | class FloatOrder extends Order[Float] { 30 | 31 | def compare(x: Float, y: Float): Int = 32 | java.lang.Float.compare(x, y) 33 | 34 | override def eqv(x:Float, y:Float): Boolean = x == y 35 | override def neqv(x:Float, y:Float): Boolean = x != y 36 | override def gt(x: Float, y: Float): Boolean = x > y 37 | override def gteqv(x: Float, y: Float): Boolean = x >= y 38 | override def lt(x: Float, y: Float): Boolean = x < y 39 | override def lteqv(x: Float, y: Float): Boolean = x <= y 40 | 41 | override def min(x: Float, y: Float): Float = 42 | java.lang.Math.min(x, y) 43 | override def max(x: Float, y: Float): Float = 44 | java.lang.Math.max(x, y) 45 | } 46 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/instances/int.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | package instances 3 | 4 | package object int extends IntInstances 5 | 6 | trait IntInstances { 7 | implicit val catsKernelStdOrderForInt: Order[Int] = new IntOrder 8 | implicit val catsKernelStdGroupForInt: CommutativeGroup[Int] = new IntGroup 9 | } 10 | 11 | class IntGroup extends CommutativeGroup[Int] { 12 | def combine(x: Int, y: Int): Int = x + y 13 | def empty: Int = 0 14 | def inverse(x: Int): Int = -x 15 | override def remove(x: Int, y: Int): Int = x - y 16 | } 17 | 18 | class IntOrder extends Order[Int] { 19 | 20 | def compare(x: Int, y: Int): Int = 21 | if (x < y) -1 else if (x > y) 1 else 0 22 | 23 | override def eqv(x: Int, y: Int): Boolean = x == y 24 | override def neqv(x: Int, y: Int): Boolean = x != y 25 | override def gt(x: Int, y: Int): Boolean = x > y 26 | override def gteqv(x: Int, y: Int): Boolean = x >= y 27 | override def lt(x: Int, y: Int): Boolean = x < y 28 | override def lteqv(x: Int, y: Int): Boolean = x <= y 29 | 30 | override def min(x: Int, y: Int): Int = 31 | java.lang.Math.min(x, y) 32 | override def max(x: Int, y: Int): Int = 33 | java.lang.Math.max(x, y) 34 | } 35 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/instances/long.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | package instances 3 | 4 | package object long extends LongInstances 5 | 6 | trait LongInstances { 7 | implicit val catsKernelStdOrderForLong: Order[Long] = new LongOrder 8 | implicit val catsKernelStdGroupForLong: CommutativeGroup[Long] = new LongGroup 9 | } 10 | 11 | class LongGroup extends CommutativeGroup[Long] { 12 | def combine(x: Long, y: Long): Long = x + y 13 | def empty: Long = 0L 14 | def inverse(x: Long): Long = -x 15 | override def remove(x: Long, y: Long): Long = x - y 16 | } 17 | 18 | class LongOrder extends Order[Long] { 19 | 20 | // use java.lang.Long.compare if we can rely on java >= 1.7 21 | def compare(x: Long, y: Long): Int = 22 | if (x < y) -1 else if (x > y) 1 else 0 23 | 24 | override def eqv(x: Long, y: Long): Boolean = x == y 25 | override def neqv(x: Long, y: Long): Boolean = x != y 26 | override def gt(x: Long, y: Long): Boolean = x > y 27 | override def gteqv(x: Long, y: Long): Boolean = x >= y 28 | override def lt(x: Long, y: Long): Boolean = x < y 29 | override def lteqv(x: Long, y: Long): Boolean = x <= y 30 | 31 | override def min(x: Long, y: Long): Long = 32 | java.lang.Math.min(x, y) 33 | override def max(x: Long, y: Long): Long = 34 | java.lang.Math.max(x, y) 35 | } 36 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/instances/map.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | package instances 3 | 4 | import scala.collection.mutable 5 | 6 | package object map extends MapInstances 7 | 8 | trait MapInstances { 9 | implicit def catsKernelStdEqForMap[K, V: Eq]: Eq[Map[K, V]] = 10 | new MapEq[K, V] 11 | implicit def catsKernelStdMonoidForMap[K, V: Semigroup]: Monoid[Map[K, V]] = 12 | new MapMonoid[K, V] 13 | } 14 | 15 | class MapEq[K, V](implicit V: Eq[V]) extends Eq[Map[K, V]] { 16 | def eqv(x: Map[K, V], y: Map[K, V]): Boolean = 17 | if (x eq y) true 18 | else x.size == y.size && x.forall { case (k, v1) => 19 | y.get(k) match { 20 | case Some(v2) => V.eqv(v1, v2) 21 | case None => false 22 | } 23 | } 24 | } 25 | 26 | class MapMonoid[K, V](implicit V: Semigroup[V]) extends Monoid[Map[K, V]] { 27 | 28 | def empty: Map[K, V] = Map.empty 29 | 30 | def combine(xs: Map[K, V], ys: Map[K, V]): Map[K, V] = 31 | if (xs.size <= ys.size) { 32 | xs.foldLeft(ys) { case (my, (k, x)) => 33 | my.updated(k, Semigroup.maybeCombine(x, my.get(k))) 34 | } 35 | } else { 36 | ys.foldLeft(xs) { case (mx, (k, y)) => 37 | mx.updated(k, Semigroup.maybeCombine(mx.get(k), y)) 38 | } 39 | } 40 | 41 | override def combineAll(xss: TraversableOnce[Map[K, V]]): Map[K, V] = { 42 | val acc = mutable.Map.empty[K, V] 43 | xss.foreach { m => 44 | val it = m.iterator 45 | while (it.hasNext) { 46 | val (k, v) = it.next 47 | acc(k) = Semigroup.maybeCombine(acc.get(k), v) 48 | } 49 | } 50 | StaticMethods.wrapMutableMap(acc) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/instances/set.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | package instances 3 | 4 | package object set extends SetInstances 5 | 6 | trait SetInstances { 7 | implicit def catsKernelStdPartialOrderForSet[A]: PartialOrder[Set[A]] = 8 | new SetPartialOrder[A] 9 | 10 | implicit def catsKernelStdSemilatticeForSet[A]: BoundedSemilattice[Set[A]] = 11 | new SetSemilattice[A] 12 | } 13 | 14 | class SetPartialOrder[A] extends PartialOrder[Set[A]] { 15 | def partialCompare(x: Set[A], y: Set[A]): Double = 16 | if (x eq y) 0.0 17 | else if (x.size < y.size) if (x.subsetOf(y)) -1.0 else Double.NaN 18 | else if (y.size < x.size) if (y.subsetOf(x)) 1.0 else Double.NaN 19 | else if (x == y) 0.0 20 | else Double.NaN 21 | 22 | override def eqv(x: Set[A], y: Set[A]): Boolean = 23 | x == y 24 | } 25 | 26 | class SetSemilattice[A] extends BoundedSemilattice[Set[A]] { 27 | def empty: Set[A] = Set.empty 28 | def combine(x: Set[A], y: Set[A]): Set[A] = x | y 29 | } 30 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/instances/short.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | package instances 3 | 4 | package object short extends ShortInstances 5 | 6 | trait ShortInstances { 7 | implicit val catsKernelStdOrderForShort: Order[Short] = new ShortOrder 8 | implicit val catsKernelStdGroupForShort: CommutativeGroup[Short] = new ShortGroup 9 | } 10 | 11 | class ShortGroup extends CommutativeGroup[Short] { 12 | def combine(x: Short, y: Short): Short = (x + y).toShort 13 | def empty: Short = 0 14 | def inverse(x: Short): Short = (-x).toShort 15 | override def remove(x: Short, y: Short): Short = (x - y).toShort 16 | } 17 | 18 | class ShortOrder extends Order[Short] { 19 | 20 | // use java.lang.Short.compare if we can rely on java >= 1.7 21 | def compare(x: Short, y: Short): Int = 22 | if (x < y) -1 else if (x > y) 1 else 0 23 | 24 | override def eqv(x: Short, y: Short): Boolean = x == y 25 | override def neqv(x: Short, y: Short): Boolean = x != y 26 | override def gt(x: Short, y: Short): Boolean = x > y 27 | override def gteqv(x: Short, y: Short): Boolean = x >= y 28 | override def lt(x: Short, y: Short): Boolean = x < y 29 | override def lteqv(x: Short, y: Short): Boolean = x <= y 30 | 31 | override def min(x: Short, y: Short): Short = 32 | java.lang.Math.min(x.toInt, y.toInt).toShort 33 | override def max(x: Short, y: Short): Short = 34 | java.lang.Math.max(x.toInt, y.toInt).toShort 35 | } 36 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/instances/string.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | package instances 3 | 4 | package object string extends StringInstances 5 | 6 | trait StringInstances { 7 | implicit val catsKernelStdOrderForString: Order[String] = new StringOrder 8 | implicit val catsKernelStdMonoidForString: Monoid[String] = new StringMonoid 9 | } 10 | 11 | class StringOrder extends Order[String] { 12 | override def eqv(x: String, y: String): Boolean = 13 | x == y 14 | def compare(x: String, y: String): Int = 15 | if (x eq y) 0 else x compareTo y 16 | } 17 | 18 | class StringMonoid extends Monoid[String] { 19 | def empty: String = "" 20 | def combine(x: String, y: String): String = x + y 21 | 22 | override def combineAll(xs: TraversableOnce[String]): String = { 23 | val sb = new StringBuilder 24 | xs.foreach(sb.append) 25 | sb.toString 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/instances/tuple.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | package instances 3 | 4 | package object tuple extends TupleInstances 5 | -------------------------------------------------------------------------------- /kernel/src/main/scala/cats/kernel/instances/unit.scala: -------------------------------------------------------------------------------- 1 | package cats.kernel 2 | package instances 3 | 4 | package object unit extends UnitInstances 5 | 6 | trait UnitInstances { 7 | implicit val catsKernelStdOrderForUnit: Order[Unit] = 8 | new UnitOrder 9 | 10 | implicit val catsKernelStdAlgebraForUnit: BoundedSemilattice[Unit] with CommutativeGroup[Unit] = 11 | new UnitAlgebra 12 | } 13 | 14 | class UnitOrder extends Order[Unit] { 15 | def compare(x: Unit, y: Unit): Int = 0 16 | 17 | override def eqv(x: Unit, y: Unit): Boolean = true 18 | override def neqv(x: Unit, y: Unit): Boolean = false 19 | override def gt(x: Unit, y: Unit): Boolean = false 20 | override def lt(x: Unit, y: Unit): Boolean = false 21 | override def gteqv(x: Unit, y: Unit): Boolean = true 22 | override def lteqv(x: Unit, y: Unit): Boolean = true 23 | 24 | override def min(x: Unit, y: Unit): Unit = () 25 | override def max(x: Unit, y: Unit): Unit = () 26 | } 27 | 28 | class UnitAlgebra extends BoundedSemilattice[Unit] with CommutativeGroup[Unit] { 29 | def empty: Unit = () 30 | def combine(x: Unit, y: Unit): Unit = () 31 | override def remove(x: Unit, y: Unit): Unit = () 32 | def inverse(x: Unit): Unit = () 33 | override protected[this] def repeatedCombineN(a: Unit, n: Int): Unit = () 34 | override def combineAllOption(as: TraversableOnce[Unit]): Option[Unit] = 35 | if (as.isEmpty) None else Some(()) 36 | } 37 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/AlternativeLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.syntax.all._ 5 | 6 | trait AlternativeLaws[F[_]] extends ApplicativeLaws[F] with MonoidKLaws[F] { 7 | implicit override def F: Alternative[F] 8 | implicit def algebra[A]: Monoid[F[A]] = F.algebra[A] 9 | 10 | def alternativeRightAbsorption[A, B](ff: F[A => B]): IsEq[F[B]] = 11 | (ff ap F.empty[A]) <-> F.empty[B] 12 | 13 | def alternativeLeftDistributivity[A, B](fa: F[A], fa2: F[A], f: A => B): IsEq[F[B]] = 14 | ((fa |+| fa2) map f) <-> ((fa map f) |+| (fa2 map f)) 15 | 16 | def alternativeRightDistributivity[A, B](fa: F[A], ff: F[A => B], fg: F[A => B]): IsEq[F[B]] = 17 | ((ff |+| fg) ap fa) <-> ((ff ap fa) |+| (fg ap fa)) 18 | 19 | } 20 | 21 | object AlternativeLaws { 22 | def apply[F[_]](implicit ev: Alternative[F]): AlternativeLaws[F] = 23 | new AlternativeLaws[F] { def F: Alternative[F] = ev } 24 | } 25 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/ApplyLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.syntax.apply._ 5 | import cats.syntax.functor._ 6 | 7 | /** 8 | * Laws that must be obeyed by any `Apply`. 9 | */ 10 | trait ApplyLaws[F[_]] extends FunctorLaws[F] with CartesianLaws[F] { 11 | implicit override def F: Apply[F] 12 | 13 | def applyComposition[A, B, C](fa: F[A], fab: F[A => B], fbc: F[B => C]): IsEq[F[C]] = { 14 | val compose: (B => C) => (A => B) => (A => C) = _.compose 15 | fbc.ap(fab.ap(fa)) <-> fbc.map(compose).ap(fab).ap(fa) 16 | } 17 | } 18 | 19 | object ApplyLaws { 20 | def apply[F[_]](implicit ev: Apply[F]): ApplyLaws[F] = 21 | new ApplyLaws[F] { def F: Apply[F] = ev } 22 | } 23 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/BifoldableLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | trait BifoldableLaws[F[_, _]] { 5 | implicit def F: Bifoldable[F] 6 | 7 | def bifoldLeftConsistentWithBifoldMap[A, B, C](fab: F[A, B], f: A => C, g: B => C)(implicit C: Monoid[C]): IsEq[C] = { 8 | val expected = F.bifoldLeft(fab, C.empty)( 9 | (c: C, a: A) => C.combine(c, f(a)), 10 | (c: C, b: B) => C.combine(c, g(b)) 11 | ) 12 | expected <-> F.bifoldMap(fab)(f, g) 13 | } 14 | 15 | def bifoldRightConsistentWithBifoldMap[A, B, C](fab: F[A, B], f: A => C, g: B => C)(implicit C: Monoid[C]): IsEq[C] = { 16 | val expected = F.bifoldRight(fab, Later(C.empty))( 17 | (a: A, ec: Eval[C]) => ec.map(c => C.combine(f(a), c)), 18 | (b: B, ec: Eval[C]) => ec.map(c => C.combine(g(b), c)) 19 | ) 20 | expected.value <-> F.bifoldMap(fab)(f, g) 21 | } 22 | } 23 | 24 | object BifoldableLaws { 25 | def apply[F[_, _]](implicit ev: Bifoldable[F]): BifoldableLaws[F] = 26 | new BifoldableLaws[F] { 27 | def F: Bifoldable[F] = ev 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/BifunctorLaws.scala: -------------------------------------------------------------------------------- 1 | package cats.laws 2 | 3 | import cats.functor.Bifunctor 4 | import cats.syntax.bifunctor._ 5 | 6 | /** 7 | * Laws that must be obeyed by any `Bifunctor`. 8 | */ 9 | trait BifunctorLaws[F[_, _]] { 10 | implicit def F: Bifunctor[F] 11 | 12 | def bifunctorIdentity[A, B](fa: F[A, B]): IsEq[F[A, B]] = 13 | fa.bimap(identity, identity) <-> fa 14 | 15 | 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]] = { 16 | fa.bimap(f, g).bimap(f2, g2) <-> fa.bimap(f andThen f2, g andThen g2) 17 | } 18 | 19 | def bifunctorLeftMapIdentity[A, B](fa: F[A, B]): IsEq[F[A, B]] = 20 | fa.leftMap(identity) <-> fa 21 | 22 | def bifunctorLeftMapComposition[A, B, C, D](fa: F[A, B], f: A => C, g: C => D): IsEq[F[D, B]] = { 23 | fa.leftMap(f).leftMap(g) <-> fa.leftMap(f andThen g) 24 | } 25 | 26 | } 27 | 28 | object BifunctorLaws { 29 | def apply[F[_, _]](implicit ev: Bifunctor[F]): BifunctorLaws[F] = 30 | new BifunctorLaws[F] { 31 | def F: Bifunctor[F] = ev 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/BimonadLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | /** 5 | * Laws that must be obeyed by any `Bimonad`. 6 | * 7 | * For more information, see definition 4.1 from this paper: 8 | * http://arxiv.org/pdf/0710.1163v3.pdf 9 | */ 10 | trait BimonadLaws[F[_]] extends MonadLaws[F] with ComonadLaws[F] { 11 | implicit override def F: Bimonad[F] 12 | 13 | def pureExtractIsId[A](a: A): IsEq[A] = 14 | F.extract(F.pure(a)) <-> a 15 | 16 | def extractFlatMapEntwining[A](ffa: F[F[A]]): IsEq[A] = 17 | F.extract(F.flatten(ffa)) <-> F.extract(F.map(ffa)(F.extract)) 18 | 19 | def pureCoflatMapEntwining[A](a: A): IsEq[F[F[A]]] = 20 | F.coflatten(F.pure(a)) <-> F.map(F.pure(a))(F.pure) 21 | } 22 | 23 | object BimonadLaws { 24 | def apply[F[_]](implicit ev: Bimonad[F]): BimonadLaws[F] = 25 | new BimonadLaws[F] { def F: Bimonad[F] = ev } 26 | } 27 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/BitraverseLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.data.Nested 5 | 6 | trait BitraverseLaws[F[_, _]] extends BifoldableLaws[F] with BifunctorLaws[F] { 7 | implicit override def F: Bitraverse[F] 8 | 9 | def bitraverseIdentity[A, B](fab: F[A, B]): IsEq[F[A, B]] = 10 | fab <-> F.bitraverse[Id, A, B, A, B](fab)(identity, identity) 11 | 12 | def bitraverseCompose[G[_], A, B, C, D, E, H]( 13 | fab: F[A, B], 14 | f: A => G[C], 15 | g: B => G[D], 16 | h: C => G[E], 17 | i: D => G[H] 18 | )(implicit 19 | G: Applicative[G] 20 | ): IsEq[G[G[F[E, H]]]] = { 21 | val fg = F.bitraverse(fab)(f, g) 22 | val hi = G.map(fg)(f => F.bitraverse(f)(h, i)) 23 | 24 | val c = 25 | F.bitraverse[Nested[G, G, ?], A, B, E, H](fab)( 26 | a => Nested(G.map(f(a))(h)), 27 | b => Nested(G.map(g(b))(i)) 28 | ) 29 | 30 | hi <-> c.value 31 | } 32 | } 33 | 34 | object BitraverseLaws { 35 | def apply[F[_, _]](implicit ev: Bitraverse[F]): BitraverseLaws[F] = 36 | new BitraverseLaws[F] { def F: Bitraverse[F] = ev } 37 | } 38 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/CartesianLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | /** 5 | * Laws that must be obeyed by any `cats.Cartesian`. 6 | */ 7 | trait CartesianLaws[F[_]] { 8 | implicit def F: Cartesian[F] 9 | 10 | def cartesianAssociativity[A, B, C](fa: F[A], fb: F[B], fc: F[C]): (F[(A, (B, C))], F[((A, B), C)]) = 11 | (F.product(fa, F.product(fb, fc)), F.product(F.product(fa, fb), fc)) 12 | } 13 | 14 | object CartesianLaws { 15 | def apply[F[_]](implicit ev: Cartesian[F]): CartesianLaws[F] = 16 | new CartesianLaws[F] { val F = ev } 17 | } 18 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/CategoryLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.arrow.Category 5 | import cats.syntax.compose._ 6 | 7 | /** 8 | * Laws that must be obeyed by any `cats.arrow.Category`. 9 | */ 10 | trait CategoryLaws[F[_, _]] extends ComposeLaws[F] { 11 | implicit override def F: Category[F] 12 | 13 | def categoryLeftIdentity[A, B](f: F[A, B]): IsEq[F[A, B]] = 14 | (F.id[A] andThen f) <-> f 15 | 16 | def categoryRightIdentity[A, B](f: F[A, B]): IsEq[F[A, B]] = 17 | (f andThen F.id[B]) <-> f 18 | } 19 | 20 | object CategoryLaws { 21 | def apply[F[_, _]](implicit ev: Category[F]): CategoryLaws[F] = 22 | new CategoryLaws[F] { def F: Category[F] = ev } 23 | } 24 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/ChoiceLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.arrow.Choice 5 | import cats.syntax.compose._ 6 | 7 | /** 8 | * Laws that must be obeyed by any `cats.arrow.Choice`. 9 | */ 10 | trait ChoiceLaws[F[_, _]] extends CategoryLaws[F] { 11 | implicit override def F: Choice[F] 12 | 13 | def choiceCompositionDistributivity[A, B, C, D](fac: F[A, C], fbc: F[B, C], fcd: F[C, D]): IsEq[F[Either[A, B], D]] = 14 | (F.choice(fac, fbc) andThen fcd) <-> F.choice(fac andThen fcd, fbc andThen fcd) 15 | } 16 | 17 | object ChoiceLaws { 18 | def apply[F[_, _]](implicit ev: Choice[F]): ChoiceLaws[F] = 19 | new ChoiceLaws[F] { def F: Choice[F] = ev } 20 | } 21 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/CoflatMapLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.data.Cokleisli 5 | import cats.implicits._ 6 | 7 | /** 8 | * Laws that must be obeyed by any `CoflatMap`. 9 | */ 10 | trait CoflatMapLaws[F[_]] extends FunctorLaws[F] { 11 | implicit override def F: CoflatMap[F] 12 | 13 | def coflatMapAssociativity[A, B, C](fa: F[A], f: F[A] => B, g: F[B] => C): IsEq[F[C]] = 14 | fa.coflatMap(f).coflatMap(g) <-> fa.coflatMap(x => g(x.coflatMap(f))) 15 | 16 | def coflattenThroughMap[A](fa: F[A]): IsEq[F[F[F[A]]]] = 17 | fa.coflatten.coflatten <-> fa.coflatten.map(_.coflatten) 18 | 19 | def coflattenCoherence[A, B](fa: F[A], f: F[A] => B): IsEq[F[B]] = 20 | fa.coflatMap(f) <-> fa.coflatten.map(f) 21 | 22 | def coflatMapIdentity[A, B](fa: F[A]): IsEq[F[F[A]]] = 23 | fa.coflatten <-> fa.coflatMap(identity) 24 | 25 | /** 26 | * The composition of `cats.data.Cokleisli` arrows is associative. This is 27 | * analogous to [[coflatMapAssociativity]]. 28 | */ 29 | def cokleisliAssociativity[A, B, C, D](f: F[A] => B, g: F[B] => C, h: F[C] => D, fa: F[A]): IsEq[D] = { 30 | val (cf, cg, ch) = (Cokleisli(f), Cokleisli(g), Cokleisli(h)) 31 | ((cf andThen cg) andThen ch).run(fa) <-> (cf andThen (cg andThen ch)).run(fa) 32 | } 33 | } 34 | 35 | object CoflatMapLaws { 36 | def apply[F[_]](implicit ev: CoflatMap[F]): CoflatMapLaws[F] = 37 | new CoflatMapLaws[F] { def F: CoflatMap[F] = ev } 38 | } 39 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/ComonadLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.data.Cokleisli 5 | import cats.implicits._ 6 | 7 | /** 8 | * Laws that must be obeyed by any `Comonad`. 9 | */ 10 | trait ComonadLaws[F[_]] extends CoflatMapLaws[F] { 11 | implicit override def F: Comonad[F] 12 | 13 | def extractCoflattenIdentity[A](fa: F[A]): IsEq[F[A]] = 14 | fa.coflatten.extract <-> fa 15 | 16 | def mapCoflattenIdentity[A](fa: F[A]): IsEq[F[A]] = 17 | fa.coflatten.map(_.extract) <-> fa 18 | 19 | def mapCoflatMapCoherence[A, B](fa: F[A], f: A => B): IsEq[F[B]] = 20 | fa.map(f) <-> fa.coflatMap(fa0 => f(fa0.extract)) 21 | 22 | def comonadLeftIdentity[A](fa: F[A]): IsEq[F[A]] = 23 | fa.coflatMap(_.extract) <-> fa 24 | 25 | def comonadRightIdentity[A, B](fa: F[A], f: F[A] => B): IsEq[B] = 26 | fa.coflatMap(f).extract <-> f(fa) 27 | 28 | /** 29 | * `extract` is the left identity element under left-to-right composition of 30 | * `cats.data.Cokleisli` arrows. This is analogous to [[comonadLeftIdentity]]. 31 | */ 32 | def cokleisliLeftIdentity[A, B](fa: F[A], f: F[A] => B): IsEq[B] = 33 | (Cokleisli(F.extract[A]) andThen Cokleisli(f)).run(fa) <-> f(fa) 34 | 35 | /** 36 | * `extract` is the right identity element under left-to-right composition of 37 | * `cats.data.Cokleisli` arrows. This is analogous to [[comonadRightIdentity]]. 38 | */ 39 | def cokleisliRightIdentity[A, B](fa: F[A], f: F[A] => B): IsEq[B] = 40 | (Cokleisli(f) andThen Cokleisli(F.extract[B])).run(fa) <-> f(fa) 41 | } 42 | 43 | object ComonadLaws { 44 | def apply[F[_]](implicit ev: Comonad[F]): ComonadLaws[F] = 45 | new ComonadLaws[F] { def F: Comonad[F] = ev } 46 | } 47 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/ComposeLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.arrow.Compose 5 | import cats.syntax.compose._ 6 | 7 | /** 8 | * Laws that must be obeyed by any `cats.arrow.Compose`. 9 | */ 10 | trait ComposeLaws[F[_, _]] { 11 | implicit def F: Compose[F] 12 | 13 | def composeAssociativity[A, B, C, D](fab: F[A, B], fbc: F[B, C], fcd: F[C, D]): IsEq[F[A, D]] = 14 | ((fab andThen fbc) andThen fcd) <-> (fab andThen (fbc andThen fcd)) 15 | } 16 | 17 | object ComposeLaws { 18 | def apply[F[_, _]](implicit ev: Compose[F]): ComposeLaws[F] = 19 | new ComposeLaws[F] { def F: Compose[F] = ev } 20 | } 21 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/ContravariantLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.functor.Contravariant 5 | import cats.syntax.contravariant._ 6 | 7 | /** 8 | * Laws that must be obeyed by any `cats.functor.Contravariant`. 9 | */ 10 | trait ContravariantLaws[F[_]] extends InvariantLaws[F] { 11 | implicit override def F: Contravariant[F] 12 | 13 | def contravariantIdentity[A](fa: F[A]): IsEq[F[A]] = 14 | fa.contramap(identity[A]) <-> fa 15 | 16 | def contravariantComposition[A, B, C](fa: F[A], f: B => A, g: C => B): IsEq[F[C]] = 17 | fa.contramap(f).contramap(g) <-> fa.contramap(f compose g) 18 | } 19 | 20 | object ContravariantLaws { 21 | def apply[F[_]](implicit ev: Contravariant[F]): ContravariantLaws[F] = 22 | new ContravariantLaws[F] { def F: Contravariant[F] = ev } 23 | } 24 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/FunctorFilterLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.implicits._ 5 | 6 | trait FunctorFilterLaws[F[_]] extends FunctorLaws[F] { 7 | implicit override def F: FunctorFilter[F] 8 | 9 | def mapFilterComposition[A, B, C]( 10 | fa: F[A], 11 | f: A => Option[B], 12 | g: B => Option[C] 13 | ): IsEq[F[C]] = { 14 | 15 | val lhs: F[C] = fa.mapFilter(f).mapFilter(g) 16 | val rhs: F[C] = fa.mapFilter(a => f(a).flatMap(g)) 17 | lhs <-> rhs 18 | } 19 | 20 | /** 21 | * Combined with the functor identity law, this implies a `mapFilter` identity 22 | * law (when `f` is the identity function). 23 | */ 24 | def mapFilterMapConsistency[A, B]( 25 | fa: F[A], 26 | f: A => B 27 | ): IsEq[F[B]] = { 28 | fa.mapFilter(f andThen (_.some)) <-> fa.map(f) 29 | } 30 | } 31 | 32 | object FunctorFilterLaws { 33 | def apply[F[_]](implicit ev: FunctorFilter[F]): FunctorFilterLaws[F] = 34 | new FunctorFilterLaws[F] { def F: FunctorFilter[F] = ev } 35 | } 36 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/FunctorLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.syntax.functor._ 5 | 6 | /** 7 | * Laws that must be obeyed by any `Functor`. 8 | */ 9 | trait FunctorLaws[F[_]] extends InvariantLaws[F] { 10 | implicit override def F: Functor[F] 11 | 12 | def covariantIdentity[A](fa: F[A]): IsEq[F[A]] = 13 | fa.map(identity) <-> fa 14 | 15 | def covariantComposition[A, B, C](fa: F[A], f: A => B, g: B => C): IsEq[F[C]] = 16 | fa.map(f).map(g) <-> fa.map(f andThen g) 17 | } 18 | 19 | object FunctorLaws { 20 | def apply[F[_]](implicit ev: Functor[F]): FunctorLaws[F] = 21 | new FunctorLaws[F] { def F: Functor[F] = ev } 22 | } 23 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/InvariantLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.functor.Invariant 5 | import cats.syntax.invariant._ 6 | 7 | /** 8 | * Laws that must be obeyed by any `cats.functor.Invariant`. 9 | */ 10 | trait InvariantLaws[F[_]] { 11 | implicit def F: Invariant[F] 12 | 13 | def invariantIdentity[A](fa: F[A]): IsEq[F[A]] = 14 | fa.imap(identity[A])(identity[A]) <-> fa 15 | 16 | def invariantComposition[A, B, C](fa: F[A], f1: A => B, f2: B => A, g1: B => C, g2: C => B): IsEq[F[C]] = 17 | fa.imap(f1)(f2).imap(g1)(g2) <-> fa.imap(g1 compose f1)(f2 compose g2) 18 | } 19 | 20 | object InvariantLaws { 21 | def apply[F[_]](implicit ev: Invariant[F]): InvariantLaws[F] = 22 | new InvariantLaws[F] { def F: Invariant[F] = ev } 23 | } 24 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/InvariantMonoidalLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | /** 5 | * Laws that must be obeyed by any `cats.InvariantMonoidal`. 6 | */ 7 | trait InvariantMonoidalLaws[F[_]] extends InvariantLaws[F] with CartesianLaws[F] { 8 | override implicit def F: InvariantMonoidal[F] 9 | import cats.syntax.cartesian._ 10 | import cats.syntax.invariant._ 11 | 12 | def invariantMonoidalLeftIdentity[A, B](fa: F[A], b: B): IsEq[F[A]] = 13 | F.pure(b).product(fa).imap(_._2)(a => (b, a)) <-> fa 14 | 15 | def invariantMonoidalRightIdentity[A, B](fa: F[A], b: B): IsEq[F[A]] = 16 | fa.product(F.pure(b)).imap(_._1)(a => (a, b)) <-> fa 17 | 18 | def invariantMonoidalAssociativity[A, B, C](fa: F[A], fb: F[B], fc: F[C]): 19 | IsEq[F[(A, (B, C))]] = 20 | fa.product(fb.product(fc)) <-> fa.product(fb).product(fc) 21 | .imap { case ((a, b), c) => (a, (b, c)) } { case (a, (b, c)) => ((a, b), c) } 22 | } 23 | 24 | object InvariantMonoidalLaws { 25 | def apply[F[_]](implicit i: InvariantMonoidal[F]): InvariantMonoidalLaws[F] = 26 | new InvariantMonoidalLaws[F] { def F: InvariantMonoidal[F] = i } 27 | } 28 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/IsEq.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | /** Represents two values of the same type that are expected to be equal. */ 5 | final case class IsEq[A](lhs: A, rhs: A) 6 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/MonadCombineLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.syntax.all._ 5 | 6 | /** 7 | * Laws that must be obeyed by any `MonadCombine`. 8 | */ 9 | trait MonadCombineLaws[F[_]] extends MonadFilterLaws[F] with AlternativeLaws[F] { 10 | implicit override def F: MonadCombine[F] 11 | 12 | def monadCombineLeftDistributivity[A, B](fa: F[A], fa2: F[A], f: A => F[B]): IsEq[F[B]] = 13 | F.combineK(fa, fa2).flatMap(f) <-> F.combineK(fa flatMap f, fa2 flatMap f) 14 | } 15 | 16 | object MonadCombineLaws { 17 | def apply[F[_]](implicit ev: MonadCombine[F]): MonadCombineLaws[F] = 18 | new MonadCombineLaws[F] { def F: MonadCombine[F] = ev } 19 | } 20 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/MonadErrorLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | // Taken from http://functorial.com/psc-pages/docs/Control/Monad/Error/Class/index.html 5 | trait MonadErrorLaws[F[_], E] extends ApplicativeErrorLaws[F, E] with MonadLaws[F] { 6 | implicit override def F: MonadError[F, E] 7 | 8 | def monadErrorLeftZero[A, B](e: E, f: A => F[B]): IsEq[F[B]] = 9 | F.flatMap(F.raiseError[A](e))(f) <-> F.raiseError[B](e) 10 | } 11 | 12 | object MonadErrorLaws { 13 | def apply[F[_], E](implicit ev: MonadError[F, E]): MonadErrorLaws[F, E] = 14 | new MonadErrorLaws[F, E] { def F: MonadError[F, E] = ev } 15 | } 16 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/MonadFilterLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.syntax.all._ 5 | 6 | /** 7 | * Laws that must be obeyed by any `MonadFilter`. 8 | */ 9 | trait MonadFilterLaws[F[_]] extends MonadLaws[F] with FunctorFilterLaws[F] { 10 | implicit override def F: MonadFilter[F] 11 | 12 | def monadFilterLeftEmpty[A, B](f: A => F[B]): IsEq[F[B]] = 13 | F.empty[A].flatMap(f) <-> F.empty[B] 14 | 15 | def monadFilterRightEmpty[A, B](fa: F[A]): IsEq[F[B]] = 16 | fa.flatMap(_ => F.empty[B]) <-> F.empty[B] 17 | 18 | def monadFilterConsistency[A, B](fa: F[A], f: A => Boolean): IsEq[F[A]] = 19 | fa.filter(f) <-> fa.flatMap(a => if (f(a)) F.pure(a) else F.empty) 20 | } 21 | 22 | object MonadFilterLaws { 23 | def apply[F[_]](implicit ev: MonadFilter[F]): MonadFilterLaws[F] = 24 | new MonadFilterLaws[F] { def F: MonadFilter[F] = ev } 25 | } 26 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/MonadLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.data.Kleisli 5 | import cats.implicits._ 6 | 7 | /** 8 | * Laws that must be obeyed by any `Monad`. 9 | */ 10 | trait MonadLaws[F[_]] extends ApplicativeLaws[F] with FlatMapLaws[F] { 11 | implicit override def F: Monad[F] 12 | 13 | def monadLeftIdentity[A, B](a: A, f: A => F[B]): IsEq[F[B]] = 14 | F.pure(a).flatMap(f) <-> f(a) 15 | 16 | def monadRightIdentity[A](fa: F[A]): IsEq[F[A]] = 17 | fa.flatMap(F.pure) <-> fa 18 | 19 | /** 20 | * `pure` is the left identity element under left-to-right composition of 21 | * `cats.data.Kleisli` arrows. This is analogous to [[monadLeftIdentity]]. 22 | */ 23 | def kleisliLeftIdentity[A, B](a: A, f: A => F[B]): IsEq[F[B]] = 24 | (Kleisli(F.pure[A]) andThen Kleisli(f)).run(a) <-> f(a) 25 | 26 | /** 27 | * `pure` is the right identity element under left-to-right composition of 28 | * `cats.data.Kleisli` arrows. This is analogous to [[monadRightIdentity]]. 29 | */ 30 | def kleisliRightIdentity[A, B](a: A, f: A => F[B]): IsEq[F[B]] = 31 | (Kleisli(f) andThen Kleisli(F.pure[B])).run(a) <-> f(a) 32 | 33 | /** 34 | * Make sure that map and flatMap are consistent. 35 | */ 36 | def mapFlatMapCoherence[A, B](fa: F[A], f: A => B): IsEq[F[B]] = 37 | fa.flatMap(a => F.pure(f(a))) <-> fa.map(f) 38 | } 39 | 40 | object MonadLaws { 41 | def apply[F[_]](implicit ev: Monad[F]): MonadLaws[F] = 42 | new MonadLaws[F] { def F: Monad[F] = ev } 43 | } 44 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/MonadReaderLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | // Taken from http://functorial.com/psc-pages/docs/Control/Monad/Reader/Class/index.html 5 | trait MonadReaderLaws[F[_], R] extends MonadLaws[F] { 6 | implicit override def F: MonadReader[F, R] 7 | 8 | val monadReaderAskIdempotent: IsEq[F[R]] = 9 | F.flatMap(F.ask)(_ => F.ask) <-> F.ask 10 | 11 | def monadReaderLocalAsk(f: R => R): IsEq[F[R]] = 12 | F.local(f)(F.ask) <-> F.map(F.ask)(f) 13 | 14 | def monadReaderLocalPure[A](a: A, f: R => R): IsEq[F[A]] = 15 | F.local(f)(F.pure(a)) <-> F.pure(a) 16 | 17 | def monadReaderLocalFlatMap[A, B](fra: F[A], f: A => F[B], g: R => R): IsEq[F[B]] = 18 | F.local(g)(F.flatMap(fra)(f)) <-> F.flatMap(F.local(g)(fra))(a => F.local(g)(f(a))) 19 | } 20 | 21 | object MonadReaderLaws { 22 | def apply[F[_], R](implicit FR: MonadReader[F, R]): MonadReaderLaws[F, R] = 23 | new MonadReaderLaws[F, R] { def F: MonadReader[F, R] = FR } 24 | } 25 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/MonadStateLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | // Taken from http://functorial.com/psc-pages/docs/Control/Monad/State/Class/index.html 5 | trait MonadStateLaws[F[_], S] extends MonadLaws[F] { 6 | implicit override def F: MonadState[F, S] 7 | 8 | val monadStateGetIdempotent: IsEq[F[S]] = 9 | F.flatMap(F.get)(_ => F.get) <-> F.get 10 | 11 | def monadStateSetTwice(s: S, t: S): IsEq[F[Unit]] = 12 | F.flatMap(F.set(s))(_ => F.set(t)) <-> F.set(t) 13 | 14 | def monadStateSetGet(s: S): IsEq[F[S]] = 15 | F.flatMap(F.set(s))(_ => F.get) <-> F.flatMap(F.set(s))(_ => F.pure(s)) 16 | 17 | val monadStateGetSet: IsEq[F[Unit]] = 18 | F.flatMap(F.get)(F.set) <-> F.pure(()) 19 | } 20 | 21 | object MonadStateLaws { 22 | def apply[F[_], S](implicit FS: MonadState[F, S]): MonadStateLaws[F, S] = 23 | new MonadStateLaws[F, S] { def F: MonadState[F, S] = FS } 24 | } 25 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/MonadWriterLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | trait MonadWriterLaws[F[_], W] extends MonadLaws[F] { 5 | implicit override def F: MonadWriter[F, W] 6 | 7 | def monadWriterWriterPure[A](a: A)(implicit W: Monoid[W]): IsEq[F[A]] = 8 | F.writer((W.empty, a)) <-> F.pure(a) 9 | 10 | def monadWriterTellFusion(x: W, y: W)(implicit W: Monoid[W]): IsEq[F[Unit]] = 11 | F.flatMap(F.tell(x))(_ => F.tell(y)) <-> F.tell(W.combine(x, y)) 12 | 13 | def monadWriterListenPure[A](a: A)(implicit W: Monoid[W]): IsEq[F[(W, A)]] = 14 | F.listen(F.pure(a)) <-> F.pure((W.empty, a)) 15 | 16 | def monadWriterListenWriter[A](aw: (W, A)): IsEq[F[(W, A)]] = 17 | F.listen(F.writer(aw)) <-> F.map(F.tell(aw._1))(_ => aw) 18 | } 19 | 20 | object MonadWriterLaws { 21 | def apply[F[_], W](implicit FW: MonadWriter[F, W]): MonadWriterLaws[F, W] = 22 | new MonadWriterLaws[F, W] { def F: MonadWriter[F, W] = FW } 23 | } 24 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/MonoidKLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | /** 5 | * Laws that must be obeyed by any `cats.MonoidK`. 6 | */ 7 | trait MonoidKLaws[F[_]] extends SemigroupKLaws[F] { 8 | override implicit def F: MonoidK[F] 9 | 10 | def monoidKLeftIdentity[A](a: F[A]): IsEq[F[A]] = 11 | F.combineK(F.empty, a) <-> a 12 | 13 | def monoidKRightIdentity[A](a: F[A]): IsEq[F[A]] = 14 | F.combineK(a, F.empty) <-> a 15 | } 16 | 17 | object MonoidKLaws { 18 | def apply[F[_]](implicit ev: MonoidK[F]): MonoidKLaws[F] = 19 | new MonoidKLaws[F] { def F: MonoidK[F] = ev } 20 | } 21 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/ProfunctorLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.functor.Profunctor 5 | import cats.syntax.profunctor._ 6 | 7 | /** 8 | * Laws that must be obeyed by any `cats.functor.Profunctor`. 9 | */ 10 | trait ProfunctorLaws[F[_, _]] { 11 | implicit def F: Profunctor[F] 12 | 13 | def profunctorIdentity[A, B](fab: F[A, B]): IsEq[F[A, B]] = 14 | fab.dimap(identity[A])(identity[B]) <-> fab 15 | 16 | def profunctorComposition[A2, A1, A0, B0, B1, B2](fab: F[A0, B0], 17 | f2: A2 => A1, f1: A1 => A0, 18 | g1: B0 => B1, g2: B1 => B2): IsEq[F[A2, B2]] = 19 | fab.dimap(f1)(g1).dimap(f2)(g2) <-> fab.dimap(f1 compose f2)(g2 compose g1) 20 | 21 | def profunctorLmapIdentity[A, B](fab: F[A, B]): IsEq[F[A, B]] = 22 | fab.lmap(identity[A]) <-> fab 23 | 24 | def profunctorRmapIdentity[A, B](fab: F[A, B]): IsEq[F[A, B]] = 25 | fab.rmap(identity[B]) <-> fab 26 | 27 | def profunctorLmapComposition[A2, A1, A0, B](fab: F[A0, B], 28 | f: A2 => A1, g: A1 => A0): IsEq[F[A2, B]] = 29 | fab.lmap(g).lmap(f) <-> fab.lmap(g compose f) 30 | 31 | def profunctorRmapComposition[A, B2, B1, B0](fab: F[A, B0], 32 | f: B0 => B1, g: B1 => B2): IsEq[F[A, B2]] = 33 | fab.rmap(f).rmap(g) <-> fab.rmap(g compose f) 34 | 35 | } 36 | 37 | object ProfunctorLaws { 38 | def apply[F[_, _]](implicit ev: Profunctor[F]): ProfunctorLaws[F] = 39 | new ProfunctorLaws[F] { def F: Profunctor[F] = ev } 40 | } 41 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/ReducibleLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.implicits._ 5 | 6 | trait ReducibleLaws[F[_]] extends FoldableLaws[F] { 7 | implicit def F: Reducible[F] 8 | 9 | def reduceLeftToConsistentWithReduceMap[A, B]( 10 | fa: F[A], 11 | f: A => B 12 | )(implicit 13 | B: Semigroup[B] 14 | ): IsEq[B] = 15 | fa.reduceMap(f) <-> fa.reduceLeftTo(f)((b, a) => b |+| f(a)) 16 | 17 | def reduceRightToConsistentWithReduceMap[A, B]( 18 | fa: F[A], 19 | f: A => B 20 | )(implicit 21 | B: Semigroup[B] 22 | ): IsEq[B] = 23 | fa.reduceMap(f) <-> fa.reduceRightTo(f)((a, eb) => eb.map(f(a) |+| _)).value 24 | 25 | def traverseConsistent[G[_]: Applicative, A, B](fa: F[A], f: A => G[B]): IsEq[G[Unit]] = 26 | fa.traverse1_(f) <-> fa.traverse_(f) 27 | 28 | def sequenceConsistent[G[_]: Applicative, A](fa: F[G[A]]): IsEq[G[Unit]] = 29 | fa.sequence1_ <-> fa.sequence_ 30 | } 31 | 32 | object ReducibleLaws { 33 | def apply[F[_]](implicit ev: Reducible[F]): ReducibleLaws[F] = 34 | new ReducibleLaws[F] { def F: Reducible[F] = ev } 35 | } 36 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/SemigroupKLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | /** 5 | * Laws that must be obeyed by any `cats.SemigroupK`. 6 | */ 7 | trait SemigroupKLaws[F[_]] { 8 | implicit def F: SemigroupK[F] 9 | 10 | def semigroupKAssociative[A](a: F[A], b: F[A], c: F[A]): IsEq[F[A]] = 11 | F.combineK(F.combineK(a, b), c) <-> F.combineK(a, F.combineK(b, c)) 12 | } 13 | 14 | object SemigroupKLaws { 15 | def apply[F[_]](implicit ev: SemigroupK[F]): SemigroupKLaws[F] = 16 | new SemigroupKLaws[F] { def F: SemigroupK[F] = ev } 17 | } 18 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/SplitLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.arrow.Split 5 | import cats.syntax.compose._ 6 | import cats.syntax.split._ 7 | 8 | /** 9 | * Laws that must be obeyed by any `cats.arrow.Split`. 10 | */ 11 | trait SplitLaws[F[_, _]] extends ComposeLaws[F] { 12 | implicit override def F: Split[F] 13 | 14 | def splitInterchange[A1, A2, A3, B1, B2, B3](f1: F[A1, A2], f2: F[A2, A3], 15 | g1: F[B1, B2], g2: F[B2, B3]): IsEq[F[(A1, B1), (A3, B3)]] = 16 | ((f1 split g1) andThen (f2 split g2)) <-> ((f1 andThen f2) split (g1 andThen g2)) 17 | } 18 | 19 | object SplitLaws { 20 | def apply[F[_, _]](implicit ev: Split[F]): SplitLaws[F] = 21 | new SplitLaws[F] { def F: Split[F] = ev } 22 | } 23 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/StrongLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.functor.Strong 5 | import cats.syntax.profunctor._ 6 | import cats.syntax.strong._ 7 | import cats.instances.function._ 8 | 9 | /** 10 | * Laws that must be obeyed by any `cats.functor.Strong`. 11 | */ 12 | trait StrongLaws[F[_, _]] extends ProfunctorLaws[F] { 13 | implicit override def F: Strong[F] 14 | 15 | def strongFirstDistributivity[A0, A1, B1, B2, C](fab: F[A1, B1], f: A0 => A1, g: B1 => B2): IsEq[F[(A0, C), (B2, C)]] = 16 | fab.dimap(f)(g).first[C] <-> fab.first[C].dimap(f.first[C])(g.first[C]) 17 | 18 | def strongSecondDistributivity[A0, A1, B1, B2, C](fab: F[A1, B1], f: A0 => A1, g: B1 => B2): IsEq[F[(C, A0), (C, B2)]] = 19 | fab.dimap(f)(g).second[C] <-> fab.second[C].dimap(f.second[C])(g.second[C]) 20 | } 21 | 22 | object StrongLaws { 23 | def apply[F[_, _]](implicit ev: Strong[F]): StrongLaws[F] = 24 | new StrongLaws[F] { def F: Strong[F] = ev } 25 | } 26 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/TraverseFilterLaws.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.data.Nested 5 | import cats.implicits._ 6 | 7 | trait TraverseFilterLaws[F[_]] extends TraverseLaws[F] with FunctorFilterLaws[F] { 8 | implicit override def F: TraverseFilter[F] 9 | 10 | def traverseFilterIdentity[G[_]:Applicative, A](fa: F[A]): IsEq[G[F[A]]] = { 11 | fa.traverseFilter(_.some.pure[G]) <-> fa.pure[G] 12 | } 13 | 14 | def traverseFilterComposition[A, B, C, M[_], N[_]]( 15 | fa: F[A], 16 | f: A => M[Option[B]], 17 | g: B => N[Option[C]] 18 | )(implicit 19 | M: Applicative[M], 20 | N: Applicative[N] 21 | ): IsEq[Nested[M, N, F[C]]] = { 22 | 23 | val lhs: Nested[M, N, F[C]] = Nested(fa.traverseFilter(f).map(_.traverseFilter(g))) 24 | val rhs: Nested[M, N, F[C]] = fa.traverseFilter[Nested[M, N, ?], C](a => 25 | Nested(f(a).map(_.traverseFilter(g)))) 26 | lhs <-> rhs 27 | } 28 | } 29 | 30 | object TraverseFilterLaws { 31 | def apply[F[_]](implicit ev: TraverseFilter[F]): TraverseFilterLaws[F] = 32 | new TraverseFilterLaws[F] { def F: TraverseFilter[F] = ev } 33 | } 34 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/AlternativeTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.laws.discipline.CartesianTests.Isomorphisms 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop 8 | import Prop._ 9 | 10 | trait AlternativeTests[F[_]] extends ApplicativeTests[F] with MonoidKTests[F] { 11 | def laws: AlternativeLaws[F] 12 | 13 | def alternative[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit 14 | ArbFA: Arbitrary[F[A]], 15 | ArbFB: Arbitrary[F[B]], 16 | ArbFC: Arbitrary[F[C]], 17 | ArbFAtoB: Arbitrary[F[A => B]], 18 | ArbFBtoC: Arbitrary[F[B => C]], 19 | EqFA: Eq[F[A]], 20 | EqFB: Eq[F[B]], 21 | EqFC: Eq[F[C]], 22 | EqFABC: Eq[F[(A, B, C)]], 23 | iso: Isomorphisms[F] 24 | ): RuleSet = { 25 | new RuleSet { 26 | val name: String = "alternative" 27 | val bases: Seq[(String, RuleSet)] = Nil 28 | val parents: Seq[RuleSet] = Seq(monoidK[A], applicative[A, B, C]) 29 | val props: Seq[(String, Prop)] = Seq( 30 | "left distributivity" -> forAll(laws.alternativeLeftDistributivity[A, B] _), 31 | "right distributivity" -> forAll(laws.alternativeRightDistributivity[A, B] _), 32 | "right absorption" -> forAll(laws.alternativeRightAbsorption[A, B] _) 33 | ) 34 | } 35 | } 36 | 37 | } 38 | 39 | object AlternativeTests { 40 | def apply[F[_]: Alternative]: AlternativeTests[F] = 41 | new AlternativeTests[F] { def laws: AlternativeLaws[F] = AlternativeLaws[F] } 42 | } 43 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/ApplicativeTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.laws.discipline.CartesianTests.Isomorphisms 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop 8 | import Prop._ 9 | 10 | trait ApplicativeTests[F[_]] extends ApplyTests[F] { 11 | def laws: ApplicativeLaws[F] 12 | 13 | def applicative[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit 14 | ArbFA: Arbitrary[F[A]], 15 | ArbFB: Arbitrary[F[B]], 16 | ArbFC: Arbitrary[F[C]], 17 | ArbFAtoB: Arbitrary[F[A => B]], 18 | ArbFBtoC: Arbitrary[F[B => C]], 19 | EqFA: Eq[F[A]], 20 | EqFB: Eq[F[B]], 21 | EqFC: Eq[F[C]], 22 | EqFABC: Eq[F[(A, B, C)]], 23 | iso: Isomorphisms[F] 24 | ): RuleSet = { 25 | new DefaultRuleSet( 26 | name = "applicative", 27 | parent = Some(apply[A, B, C]), 28 | "applicative identity" -> forAll(laws.applicativeIdentity[A] _), 29 | "applicative homomorphism" -> forAll(laws.applicativeHomomorphism[A, B] _), 30 | "applicative interchange" -> forAll(laws.applicativeInterchange[A, B] _), 31 | "applicative map" -> forAll(laws.applicativeMap[A, B] _), 32 | "ap consistent with product + map" -> forAll(laws.apProductConsistent[A, B] _), 33 | "monoidal left identity" -> forAll((fa: F[A]) => iso.leftIdentity(laws.monoidalLeftIdentity(fa))), 34 | "monoidal right identity" -> forAll((fa: F[A]) => iso.rightIdentity(laws.monoidalRightIdentity(fa)))) 35 | } 36 | } 37 | 38 | object ApplicativeTests { 39 | def apply[F[_]: Applicative]: ApplicativeTests[F] = 40 | new ApplicativeTests[F] { def laws: ApplicativeLaws[F] = ApplicativeLaws[F] } 41 | } 42 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/ApplyTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.laws.discipline.CartesianTests.Isomorphisms 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop 8 | import Prop._ 9 | 10 | trait ApplyTests[F[_]] extends FunctorTests[F] with CartesianTests[F] { 11 | def laws: ApplyLaws[F] 12 | 13 | def apply[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit 14 | ArbFA: Arbitrary[F[A]], 15 | ArbFB: Arbitrary[F[B]], 16 | ArbFC: Arbitrary[F[C]], 17 | ArbFAtoB: Arbitrary[F[A => B]], 18 | ArbFBtoC: Arbitrary[F[B => C]], 19 | EqFA: Eq[F[A]], 20 | EqFC: Eq[F[C]], 21 | EqFABC: Eq[F[(A, B, C)]], 22 | iso: Isomorphisms[F] 23 | ): RuleSet = new RuleSet { 24 | val name = "apply" 25 | val parents = Seq(functor[A, B, C], cartesian[A, B, C]) 26 | val bases = Seq.empty 27 | val props = Seq("apply composition" -> forAll(laws.applyComposition[A, B, C] _)) 28 | } 29 | } 30 | 31 | object ApplyTests { 32 | def apply[F[_]: Apply]: ApplyTests[F] = 33 | new ApplyTests[F] { def laws: ApplyLaws[F] = ApplyLaws[F] } 34 | } 35 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/BifoldableTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import org.scalacheck.Arbitrary 6 | import org.scalacheck.Prop._ 7 | import org.typelevel.discipline.Laws 8 | 9 | trait BifoldableTests[F[_, _]] extends Laws { 10 | def laws: BifoldableLaws[F] 11 | 12 | def bifoldable[A: Arbitrary, B: Arbitrary, C: Arbitrary: Monoid: Eq](implicit 13 | ArbFAB: Arbitrary[F[A, B]] 14 | ): RuleSet = 15 | new DefaultRuleSet( 16 | name = "bifoldable", 17 | parent = None, 18 | "bifoldLeft consistent with bifoldMap" -> forAll(laws.bifoldLeftConsistentWithBifoldMap[A, B, C] _), 19 | "bifoldRight consistent with bifoldMap" -> forAll(laws.bifoldRightConsistentWithBifoldMap[A, B, C] _) 20 | ) 21 | } 22 | 23 | object BifoldableTests { 24 | def apply[F[_, _]: Bifoldable]: BifoldableTests[F] = 25 | new BifoldableTests[F] { def laws: BifoldableLaws[F] = BifoldableLaws[F] } 26 | } 27 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/BifunctorTests.scala: -------------------------------------------------------------------------------- 1 | package cats.laws.discipline 2 | 3 | import cats.Eq 4 | import cats.functor.Bifunctor 5 | import cats.laws.BifunctorLaws 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop._ 8 | import org.typelevel.discipline.Laws 9 | 10 | trait BifunctorTests[F[_, _]] extends Laws { 11 | def laws: BifunctorLaws[F] 12 | 13 | def bifunctor[A, A2, A3, B, B2, B3](implicit 14 | ArbFAB: Arbitrary[F[A, B]], 15 | ArbA2: Arbitrary[A => A2], 16 | ArbA3: Arbitrary[A2 => A3], 17 | ArbB2: Arbitrary[B => B2], 18 | ArbB3: Arbitrary[B2 => B3], 19 | EqFAB: Eq[F[A, B]], 20 | EqFCZ: Eq[F[A3, B3]], 21 | EqFA3B: Eq[F[A3, B]], 22 | EqFAB3: Eq[F[A, B3]] 23 | ): RuleSet = { 24 | new DefaultRuleSet( 25 | name = "Bifunctor", 26 | parent = None, 27 | "Bifunctor Identity" -> forAll(laws.bifunctorIdentity[A, B] _), 28 | "Bifunctor associativity" -> forAll(laws.bifunctorComposition[A, A2, A3, B, B2, B3] _), 29 | "Bifunctor leftMap Identity" -> forAll(laws.bifunctorLeftMapIdentity[A, B] _), 30 | "Bifunctor leftMap associativity" -> forAll(laws.bifunctorLeftMapComposition[A, B, A2, A3] _) 31 | ) 32 | } 33 | } 34 | 35 | object BifunctorTests { 36 | def apply[F[_, _] : Bifunctor]: BifunctorTests[F] = 37 | new BifunctorTests[F] { 38 | def laws: BifunctorLaws[F] = BifunctorLaws[F] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/BimonadTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.laws.discipline.CartesianTests.Isomorphisms 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop 8 | import Prop._ 9 | 10 | trait BimonadTests[F[_]] extends MonadTests[F] with ComonadTests[F] { 11 | def laws: BimonadLaws[F] 12 | 13 | def bimonad[A: Arbitrary: Eq, B: Arbitrary: Eq, C: Arbitrary: Eq](implicit 14 | ArbFA: Arbitrary[F[A]], 15 | ArbFFA: Arbitrary[F[F[A]]], 16 | ArbFB: Arbitrary[F[B]], 17 | ArbFC: Arbitrary[F[C]], 18 | ArbFAtoB: Arbitrary[F[A => B]], 19 | ArbFBtoC: Arbitrary[F[B => C]], 20 | EqFFFA: Eq[F[F[A]]], 21 | EqFFA: Eq[F[F[F[A]]]], 22 | EqFA: Eq[F[A]], 23 | EqFB: Eq[F[B]], 24 | EqFC: Eq[F[C]], 25 | EqFABC: Eq[F[(A, B, C)]], 26 | iso: Isomorphisms[F] 27 | ): RuleSet = { 28 | new RuleSet { 29 | def name: String = "bimonad" 30 | def bases: Seq[(String, RuleSet)] = Nil 31 | def parents: Seq[RuleSet] = Seq(monad[A, B, C], comonad[A, B, C]) 32 | def props: Seq[(String, Prop)] = Seq( 33 | "pure andThen extract = id" -> forAll(laws.pureExtractIsId[A] _), 34 | "extract/flatMap entwining" -> forAll(laws.extractFlatMapEntwining[A] _), 35 | "pure/coflatMap entwining" -> forAll(laws.pureCoflatMapEntwining[A] _) 36 | ) 37 | } 38 | } 39 | } 40 | 41 | object BimonadTests { 42 | def apply[F[_]: Bimonad]: BimonadTests[F] = 43 | new BimonadTests[F] { 44 | def laws: BimonadLaws[F] = BimonadLaws[F] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/BitraverseTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import org.scalacheck.Arbitrary 6 | import org.scalacheck.Prop.forAll 7 | 8 | trait BitraverseTests[F[_, _]] extends BifoldableTests[F] with BifunctorTests[F] { 9 | def laws: BitraverseLaws[F] 10 | 11 | def bitraverse[G[_], A, B, C, D, E, H](implicit 12 | G: Applicative[G], 13 | C: Monoid[C], 14 | ArbFAB: Arbitrary[F[A, B]], 15 | ArbFAD: Arbitrary[F[A, D]], 16 | ArbGC: Arbitrary[G[C]], 17 | ArbGD: Arbitrary[G[D]], 18 | ArbGE: Arbitrary[G[E]], 19 | ArbGH: Arbitrary[G[H]], 20 | ArbA: Arbitrary[A], 21 | ArbB: Arbitrary[B], 22 | ArbC: Arbitrary[C], 23 | ArbE: Arbitrary[E], 24 | ArbH: Arbitrary[H], 25 | EqFAB: Eq[F[A, B]], 26 | EqFAD: Eq[F[A, D]], 27 | EqFAH: Eq[F[A, H]], 28 | EqFCD: Eq[F[C, D]], 29 | EqFCH: Eq[F[C, H]], 30 | EqGGFEH: Eq[G[G[F[E, H]]]], 31 | EqC: Eq[C] 32 | ): RuleSet = 33 | new RuleSet { 34 | val name = "bitraverse" 35 | val parents = Seq(bifoldable[A, B, C], bifunctor[A, B, C, D, E, H]) 36 | val bases = Seq.empty 37 | val props = Seq( 38 | "bitraverse identity" -> forAll(laws.bitraverseIdentity[A, B] _), 39 | "bitraverse composition" -> forAll(laws.bitraverseCompose[G, A, B, C, D, E, H] _) 40 | ) 41 | } 42 | } 43 | 44 | object BitraverseTests { 45 | def apply[F[_, _]: Bitraverse]: BitraverseTests[F] = 46 | new BitraverseTests[F] { def laws: BitraverseLaws[F] = BitraverseLaws[F] } 47 | } 48 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/CategoryTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.arrow.Category 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop 8 | import Prop._ 9 | 10 | trait CategoryTests[F[_, _]] extends ComposeTests[F] { 11 | def laws: CategoryLaws[F] 12 | 13 | def category[A, B, C, D](implicit 14 | ArbFAB: Arbitrary[F[A, B]], 15 | ArbFBC: Arbitrary[F[B, C]], 16 | ArbFCD: Arbitrary[F[C, D]], 17 | EqFAB: Eq[F[A, B]], 18 | EqFAD: Eq[F[A, D]] 19 | ): RuleSet = 20 | new DefaultRuleSet( 21 | name = "category", 22 | parent = Some(compose[A, B, C, D]), 23 | "category left identity" -> forAll(laws.categoryLeftIdentity[A, B] _), 24 | "category right identity" -> forAll(laws.categoryRightIdentity[A, B] _)) 25 | } 26 | 27 | object CategoryTests { 28 | def apply[F[_, _]: Category]: CategoryTests[F] = 29 | new CategoryTests[F] { def laws: CategoryLaws[F] = CategoryLaws[F] } 30 | } 31 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/ChoiceTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.arrow.Choice 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop._ 8 | 9 | trait ChoiceTests[F[_, _]] extends CategoryTests[F] { 10 | def laws: ChoiceLaws[F] 11 | 12 | def choice[A, B, C, D](implicit 13 | ArbFAB: Arbitrary[F[A, B]], 14 | ArbFAC: Arbitrary[F[A, C]], 15 | ArbFBC: Arbitrary[F[B, C]], 16 | ArbFCD: Arbitrary[F[C, D]], 17 | EqFAB: Eq[F[A, B]], 18 | EqFAD: Eq[F[A, D]], 19 | EqFEitherABD: Eq[F[Either[A, B], D]] 20 | ): RuleSet = 21 | new DefaultRuleSet( 22 | name = "choice", 23 | parent = Some(category[A, B, C, D]), 24 | "choice composition distributivity" -> forAll(laws.choiceCompositionDistributivity[A, B, C, D] _)) 25 | } 26 | 27 | object ChoiceTests { 28 | def apply[F[_, _]: Choice]: ChoiceTests[F] = 29 | new ChoiceTests[F] { def laws: ChoiceLaws[F] = ChoiceLaws[F] } 30 | } 31 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/CoflatMapTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import org.scalacheck.Arbitrary 6 | import org.scalacheck.Prop 7 | import Prop._ 8 | import org.typelevel.discipline.Laws 9 | 10 | trait CoflatMapTests[F[_]] extends Laws with FunctorTests[F] { 11 | def laws: CoflatMapLaws[F] 12 | 13 | def coflatMap[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit 14 | ArbFA: Arbitrary[F[A]], 15 | EqFA: Eq[F[A]], 16 | EqFC: Eq[F[C]], 17 | EqFFA: Eq[F[F[A]]], 18 | EqFB: Eq[F[B]], 19 | EqFFFA: Eq[F[F[F[A]]]] 20 | ): RuleSet = { 21 | new DefaultRuleSet( 22 | name = "coflatMap", 23 | parent = Some(functor[A, B, C]), 24 | "coflatMap associativity" -> forAll(laws.coflatMapAssociativity[A, B, C] _), 25 | "coflatMap identity" -> forAll(laws.coflatMapIdentity[A, B] _), 26 | "coflatten coherence" -> forAll(laws.coflattenCoherence[A, B] _), 27 | "coflatten throughMap" -> forAll(laws.coflattenThroughMap[A] _) 28 | ) 29 | } 30 | } 31 | 32 | object CoflatMapTests { 33 | def apply[F[_]: CoflatMap]: CoflatMapTests[F] = 34 | new CoflatMapTests[F] { def laws: CoflatMapLaws[F] = CoflatMapLaws[F] } 35 | } 36 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/ComonadTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import org.scalacheck.Arbitrary 6 | import org.scalacheck.Prop 7 | import Prop._ 8 | 9 | trait ComonadTests[F[_]] extends CoflatMapTests[F] { 10 | 11 | def laws: ComonadLaws[F] 12 | 13 | def comonad[A: Arbitrary: Eq, B: Arbitrary: Eq, C: Arbitrary: Eq](implicit 14 | ArbFA: Arbitrary[F[A]], 15 | EqFA: Eq[F[A]], 16 | EqFFA: Eq[F[F[A]]], 17 | EqFFFA: Eq[F[F[F[A]]]], 18 | EqFB: Eq[F[B]], 19 | EqFC: Eq[F[C]] 20 | ): RuleSet = { 21 | new DefaultRuleSet( 22 | name = "comonad", 23 | parent = Some(coflatMap[A, B, C]), 24 | 25 | "extractCoflattenIdentity" -> forAll(laws.extractCoflattenIdentity[A] _), 26 | "mapCoflattenIdentity" -> forAll(laws.mapCoflattenIdentity[A] _), 27 | "coflattenThroughMap" -> forAll(laws.coflattenThroughMap[A] _), 28 | 29 | "coflattenCoherence" -> forAll(laws.coflattenCoherence[A, B] _), 30 | "coflatMapIdentity" -> forAll(laws.coflatMapIdentity[A, B] _), 31 | "mapCoflatMapCoherence" -> forAll(laws.mapCoflatMapCoherence[A, B] _), 32 | 33 | "comonad left identity" -> forAll(laws.comonadLeftIdentity[A] _), 34 | "comonad right identity" -> forAll(laws.comonadRightIdentity[A, B] _)) 35 | } 36 | } 37 | 38 | object ComonadTests { 39 | def apply[F[_]: Comonad]: ComonadTests[F] = 40 | new ComonadTests[F] { 41 | def laws: ComonadLaws[F] = ComonadLaws[F] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/ComposeTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.arrow.Compose 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop 8 | import Prop._ 9 | import org.typelevel.discipline.Laws 10 | 11 | trait ComposeTests[F[_, _]] extends Laws { 12 | def laws: ComposeLaws[F] 13 | 14 | def compose[A, B, C, D](implicit 15 | ArbFAB: Arbitrary[F[A, B]], 16 | ArbFBC: Arbitrary[F[B, C]], 17 | ArbFCD: Arbitrary[F[C, D]], 18 | EqFAD: Eq[F[A, D]] 19 | ): RuleSet = 20 | new DefaultRuleSet( 21 | name = "compose", 22 | parent = None, 23 | "compose associativity" -> forAll(laws.composeAssociativity[A, B, C, D] _)) 24 | } 25 | 26 | object ComposeTests { 27 | def apply[F[_, _]: Compose]: ComposeTests[F] = 28 | new ComposeTests[F] { def laws: ComposeLaws[F] = ComposeLaws[F] } 29 | } 30 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/ContravariantTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.functor.Contravariant 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop._ 8 | 9 | trait ContravariantTests[F[_]] extends InvariantTests[F] { 10 | def laws: ContravariantLaws[F] 11 | 12 | def contravariant[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit 13 | ArbFA: Arbitrary[F[A]], 14 | EqFA: Eq[F[A]], 15 | EqFC: Eq[F[C]] 16 | ): RuleSet = { 17 | new DefaultRuleSet( 18 | name = "contravariant", 19 | parent = Some(invariant[A, B, C]), 20 | "contravariant identity" -> forAll(laws.contravariantIdentity[A] _), 21 | "contravariant composition" -> forAll(laws.contravariantComposition[A, B, C] _)) 22 | } 23 | } 24 | 25 | object ContravariantTests { 26 | def apply[F[_]: Contravariant]: ContravariantTests[F] = 27 | new ContravariantTests[F] { def laws: ContravariantLaws[F] = ContravariantLaws[F] } 28 | } 29 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/FlatMapTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.laws.discipline.CartesianTests.Isomorphisms 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop 8 | import Prop._ 9 | 10 | trait FlatMapTests[F[_]] extends ApplyTests[F] { 11 | def laws: FlatMapLaws[F] 12 | 13 | def flatMap[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit 14 | ArbFA: Arbitrary[F[A]], 15 | ArbFB: Arbitrary[F[B]], 16 | ArbFC: Arbitrary[F[C]], 17 | ArbFAtoB: Arbitrary[F[A => B]], 18 | ArbFBtoC: Arbitrary[F[B => C]], 19 | EqFA: Eq[F[A]], 20 | EqFB: Eq[F[B]], 21 | EqFC: Eq[F[C]], 22 | EqFABC: Eq[F[(A, B, C)]], 23 | iso: Isomorphisms[F] 24 | ): RuleSet = { 25 | implicit def functorF: Functor[F] = laws.F 26 | implicit val EqFAB: Eq[F[(A, B)]] = 27 | ContravariantCartesian[Eq].composeFunctor[F].product(EqFA, EqFB) 28 | 29 | new DefaultRuleSet( 30 | name = "flatMap", 31 | parent = Some(apply[A, B, C]), 32 | "flatMap associativity" -> forAll(laws.flatMapAssociativity[A, B, C] _), 33 | "flatMap consistent apply" -> forAll(laws.flatMapConsistentApply[A, B] _), 34 | "followedBy consistent flatMap" -> forAll(laws.followedByConsistency[A, B] _), 35 | "mproduct consistent flatMap" -> forAll(laws.mproductConsistency[A, B] _), 36 | "tailRecM consistent flatMap" -> forAll(laws.tailRecMConsistentFlatMap[A] _)) 37 | } 38 | } 39 | 40 | object FlatMapTests { 41 | def apply[F[_]: FlatMap]: FlatMapTests[F] = 42 | new FlatMapTests[F] { def laws: FlatMapLaws[F] = FlatMapLaws[F] } 43 | } 44 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/FoldableTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import org.scalacheck.Arbitrary 6 | import org.scalacheck.Prop._ 7 | import org.typelevel.discipline.Laws 8 | 9 | trait FoldableTests[F[_]] extends Laws { 10 | def laws: FoldableLaws[F] 11 | 12 | def foldable[A: Arbitrary, B: Arbitrary](implicit 13 | ArbFA: Arbitrary[F[A]], 14 | B: Monoid[B], 15 | EqB: Eq[B] 16 | ): RuleSet = { 17 | new DefaultRuleSet( 18 | name = "foldable", 19 | parent = None, 20 | "foldLeft consistent with foldMap" -> forAll(laws.leftFoldConsistentWithFoldMap[A, B] _), 21 | "foldRight consistent with foldMap" -> forAll(laws.rightFoldConsistentWithFoldMap[A, B] _), 22 | "exists consistent with find" -> forAll(laws.existsConsistentWithFind[A] _), 23 | "forall consistent with exists" -> forAll(laws.forallConsistentWithExists[A] _), 24 | "forall true if empty" -> forAll(laws.forallEmpty[A] _), 25 | "exists is lazy" -> forAll(laws.existsLazy[A] _), 26 | "forall is lazy" -> forAll(laws.forallLazy[A] _) 27 | ) 28 | } 29 | } 30 | 31 | 32 | object FoldableTests { 33 | def apply[F[_]: Foldable]: FoldableTests[F] = 34 | new FoldableTests[F] { def laws: FoldableLaws[F] = FoldableLaws[F] } 35 | } 36 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/FunctorFilterTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import org.scalacheck.Arbitrary 6 | import org.scalacheck.Prop 7 | import Prop._ 8 | 9 | trait FunctorFilterTests[F[_]] extends FunctorTests[F] { 10 | def laws: FunctorFilterLaws[F] 11 | 12 | def functorFilter[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit 13 | ArbFA: Arbitrary[F[A]], 14 | ArbAOB: Arbitrary[A => Option[B]], 15 | ArbBOC: Arbitrary[B => Option[C]], 16 | ArbAB: Arbitrary[A => C], 17 | EqFA: Eq[F[A]], 18 | EqFC: Eq[F[C]] 19 | ): RuleSet = { 20 | new DefaultRuleSet( 21 | name = "functorFilter", 22 | parent = Some(functor[A, B, C]), 23 | "mapFilter composition" -> forAll(laws.mapFilterComposition[A, B, C] _), 24 | "mapFilter map consistency" -> forAll(laws.mapFilterMapConsistency[A, C] _)) 25 | } 26 | } 27 | 28 | object FunctorFilterTests { 29 | def apply[F[_]: FunctorFilter]: FunctorFilterTests[F] = 30 | new FunctorFilterTests[F] { def laws: FunctorFilterLaws[F] = FunctorFilterLaws[F] } 31 | } 32 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/FunctorTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import org.scalacheck.Arbitrary 6 | import org.scalacheck.Prop 7 | import Prop._ 8 | 9 | trait FunctorTests[F[_]] extends InvariantTests[F] { 10 | def laws: FunctorLaws[F] 11 | 12 | def functor[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit 13 | ArbFA: Arbitrary[F[A]], 14 | EqFA: Eq[F[A]], 15 | EqFC: Eq[F[C]] 16 | ): RuleSet = { 17 | new DefaultRuleSet( 18 | name = "functor", 19 | parent = Some(invariant[A, B, C]), 20 | "covariant identity" -> forAll(laws.covariantIdentity[A] _), 21 | "covariant composition" -> forAll(laws.covariantComposition[A, B, C] _)) 22 | } 23 | } 24 | 25 | object FunctorTests { 26 | def apply[F[_]: Functor]: FunctorTests[F] = 27 | new FunctorTests[F] { def laws: FunctorLaws[F] = FunctorLaws[F] } 28 | } 29 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/InvariantMonoidalTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.laws.discipline.CartesianTests.Isomorphisms 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop._ 8 | 9 | trait InvariantMonoidalTests[F[_]] extends InvariantTests[F] with CartesianTests[F] { 10 | def laws: InvariantMonoidalLaws[F] 11 | 12 | def invariantMonoidal[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit 13 | ArbFA: Arbitrary[F[A]], 14 | ArbFB: Arbitrary[F[B]], 15 | ArbFC: Arbitrary[F[C]], 16 | EqFABC: Eq[F[(A, (B, C))]], 17 | EqFABC2: Eq[F[(A, B, C)]], 18 | iso: Isomorphisms[F], 19 | EqFA: Eq[F[A]], 20 | EqFC: Eq[F[C]] 21 | ): RuleSet = 22 | new RuleSet { 23 | val name = "invariantMonoidal" 24 | val parents = Seq(invariant[A, B, C], cartesian[A, B, C]) 25 | val bases = Seq.empty 26 | val props = Seq( 27 | "invariant cartesian left identity" -> forAll((fa: F[A], b: B) => laws.invariantMonoidalLeftIdentity(fa, b)), 28 | "invariant cartesian right identity" -> forAll((fa: F[A], b: B) => laws.invariantMonoidalRightIdentity(fa, b)), 29 | "invariant cartesian associativity" -> forAll((fa: F[A], fb: F[B], fc: F[C]) => laws.invariantMonoidalAssociativity(fa, fb, fc)) 30 | ) 31 | } 32 | } 33 | 34 | object InvariantMonoidalTests { 35 | def apply[F[_]: InvariantMonoidal]: InvariantMonoidalTests[F] = 36 | new InvariantMonoidalTests[F] { def laws: InvariantMonoidalLaws[F] = InvariantMonoidalLaws[F] } 37 | } 38 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/InvariantTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.functor.Invariant 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop 8 | import Prop._ 9 | import org.typelevel.discipline.Laws 10 | 11 | trait InvariantTests[F[_]] extends Laws { 12 | def laws: InvariantLaws[F] 13 | 14 | def invariant[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit 15 | ArbFA: Arbitrary[F[A]], 16 | EqFA: Eq[F[A]], 17 | EqFC: Eq[F[C]] 18 | ): RuleSet = { 19 | new DefaultRuleSet( 20 | name = "invariant", 21 | parent = None, 22 | "invariant identity" -> forAll(laws.invariantIdentity[A] _), 23 | "invariant composition" -> forAll(laws.invariantComposition[A, B, C] _)) 24 | } 25 | } 26 | 27 | object InvariantTests { 28 | def apply[F[_]: Invariant]: InvariantTests[F] = 29 | new InvariantTests[F] { def laws: InvariantLaws[F] = InvariantLaws[F] } 30 | } 31 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/MonadCombineTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.laws.discipline.CartesianTests.Isomorphisms 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop 8 | import Prop._ 9 | 10 | trait MonadCombineTests[F[_]] extends MonadFilterTests[F] with AlternativeTests[F] { 11 | def laws: MonadCombineLaws[F] 12 | 13 | def monadCombine[A: Arbitrary: Eq, B: Arbitrary: Eq, C: Arbitrary: Eq](implicit 14 | ArbFA: Arbitrary[F[A]], 15 | ArbFB: Arbitrary[F[B]], 16 | ArbFC: Arbitrary[F[C]], 17 | ArbFAtoB: Arbitrary[F[A => B]], 18 | ArbFBtoC: Arbitrary[F[B => C]], 19 | EqFA: Eq[F[A]], 20 | EqFB: Eq[F[B]], 21 | EqFC: Eq[F[C]], 22 | EqFABC: Eq[F[(A, B, C)]], 23 | iso: Isomorphisms[F] 24 | ): RuleSet = { 25 | new RuleSet { 26 | def name: String = "monadCombine" 27 | def bases: Seq[(String, RuleSet)] = Nil 28 | def parents: Seq[RuleSet] = Seq(monadFilter[A, B, C], alternative[A, B, C]) 29 | def props: Seq[(String, Prop)] = Seq( 30 | "monadCombine left distributivity" -> forAll(laws.monadCombineLeftDistributivity[A, B] _) 31 | ) 32 | } 33 | } 34 | } 35 | 36 | object MonadCombineTests { 37 | def apply[F[_]: MonadCombine]: MonadCombineTests[F] = 38 | new MonadCombineTests[F] { 39 | def laws: MonadCombineLaws[F] = MonadCombineLaws[F] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/MonadErrorTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.data.EitherT 6 | import cats.laws.discipline.CartesianTests.Isomorphisms 7 | import org.scalacheck.{Arbitrary, Prop} 8 | import org.scalacheck.Prop.forAll 9 | 10 | trait MonadErrorTests[F[_], E] extends ApplicativeErrorTests[F, E] with MonadTests[F] { 11 | def laws: MonadErrorLaws[F, E] 12 | 13 | def monadError[A: Arbitrary: Eq, B: Arbitrary: Eq, C: Arbitrary: Eq](implicit 14 | ArbFA: Arbitrary[F[A]], 15 | ArbFB: Arbitrary[F[B]], 16 | ArbFC: Arbitrary[F[C]], 17 | ArbFAtoB: Arbitrary[F[A => B]], 18 | ArbFBtoC: Arbitrary[F[B => C]], 19 | ArbE: Arbitrary[E], 20 | EqFA: Eq[F[A]], 21 | EqFB: Eq[F[B]], 22 | EqFC: Eq[F[C]], 23 | EqE: Eq[E], 24 | EqFEitherEU: Eq[F[Either[E, Unit]]], 25 | EqFEitherEA: Eq[F[Either[E, A]]], 26 | EqEitherTFEA: Eq[EitherT[F, E, A]], 27 | EqFABC: Eq[F[(A, B, C)]], 28 | iso: Isomorphisms[F] 29 | ): RuleSet = { 30 | new RuleSet { 31 | def name: String = "monadError" 32 | def bases: Seq[(String, RuleSet)] = Nil 33 | def parents: Seq[RuleSet] = Seq(applicativeError[A, B, C], monad[A, B, C]) 34 | def props: Seq[(String, Prop)] = Seq( 35 | "monadError left zero" -> forAll(laws.monadErrorLeftZero[A, B] _) 36 | ) 37 | } 38 | } 39 | } 40 | 41 | object MonadErrorTests { 42 | def apply[F[_], E](implicit FE: MonadError[F, E]): MonadErrorTests[F, E] = 43 | new MonadErrorTests[F, E] { 44 | def laws: MonadErrorLaws[F, E] = MonadErrorLaws[F, E] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/MonadFilterTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.laws.discipline.CartesianTests.Isomorphisms 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop 8 | import Prop._ 9 | 10 | trait MonadFilterTests[F[_]] extends MonadTests[F] with FunctorFilterTests[F] { 11 | def laws: MonadFilterLaws[F] 12 | 13 | def monadFilter[A: Arbitrary: Eq, B: Arbitrary: Eq, C: Arbitrary: Eq](implicit 14 | ArbFA: Arbitrary[F[A]], 15 | ArbFB: Arbitrary[F[B]], 16 | ArbFC: Arbitrary[F[C]], 17 | ArbFAtoB: Arbitrary[F[A => B]], 18 | ArbFBtoC: Arbitrary[F[B => C]], 19 | EqFA: Eq[F[A]], 20 | EqFB: Eq[F[B]], 21 | EqFC: Eq[F[C]], 22 | EqFABC: Eq[F[(A, B, C)]], 23 | iso: Isomorphisms[F] 24 | ): RuleSet = { 25 | new RuleSet { 26 | def name: String = "monadFilter" 27 | def bases: Seq[(String, RuleSet)] = Nil 28 | def parents: Seq[RuleSet] = Seq(monad[A, B, C], functorFilter[A, B, C]) 29 | def props: Seq[(String, Prop)] = Seq( 30 | "monadFilter left empty" -> forAll(laws.monadFilterLeftEmpty[A, B] _), 31 | "monadFilter right empty" -> forAll(laws.monadFilterRightEmpty[A, B] _), 32 | "monadFilter consistency" -> forAll(laws.monadFilterConsistency[A, B] _) 33 | ) 34 | } 35 | } 36 | } 37 | 38 | object MonadFilterTests { 39 | def apply[F[_]: MonadFilter]: MonadFilterTests[F] = 40 | new MonadFilterTests[F] { 41 | def laws: MonadFilterLaws[F] = MonadFilterLaws[F] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/MonadReaderTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.laws.discipline.CartesianTests.Isomorphisms 6 | import org.scalacheck.{Arbitrary, Prop} 7 | import org.scalacheck.Prop.forAll 8 | 9 | trait MonadReaderTests[F[_], R] extends MonadTests[F] { 10 | def laws: MonadReaderLaws[F, R] 11 | 12 | def monadReader[A: Arbitrary: Eq, B: Arbitrary: Eq, C: Arbitrary: Eq](implicit 13 | ArbFA: Arbitrary[F[A]], 14 | ArbFB: Arbitrary[F[B]], 15 | ArbFC: Arbitrary[F[C]], 16 | ArbFAtoB: Arbitrary[F[A => B]], 17 | ArbFBtoC: Arbitrary[F[B => C]], 18 | ArbR: Arbitrary[R], 19 | EqFA: Eq[F[A]], 20 | EqFB: Eq[F[B]], 21 | EqFC: Eq[F[C]], 22 | EqFR: Eq[F[R]], 23 | EqFABC: Eq[F[(A, B, C)]], 24 | iso: Isomorphisms[F] 25 | ): RuleSet = { 26 | new RuleSet { 27 | def name: String = "monadReader" 28 | def bases: Seq[(String, RuleSet)] = Nil 29 | def parents: Seq[RuleSet] = Seq(monad[A, B, C]) 30 | def props: Seq[(String, Prop)] = Seq( 31 | "monadReader ask idempotent" -> laws.monadReaderAskIdempotent, 32 | "monadReader local ask" -> forAll(laws.monadReaderLocalAsk _), 33 | "monadReader local pure" -> forAll(laws.monadReaderLocalPure[A] _), 34 | "monadReader local flatMap" -> forAll(laws.monadReaderLocalFlatMap[A, B] _) 35 | ) 36 | } 37 | } 38 | } 39 | 40 | object MonadReaderTests { 41 | def apply[F[_], R](implicit FR: MonadReader[F, R]): MonadReaderTests[F, R] = 42 | new MonadReaderTests[F, R] { 43 | def laws: MonadReaderLaws[F, R] = MonadReaderLaws[F, R] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/MonadTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.laws.discipline.CartesianTests.Isomorphisms 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop 8 | import Prop._ 9 | 10 | trait MonadTests[F[_]] extends ApplicativeTests[F] with FlatMapTests[F] { 11 | def laws: MonadLaws[F] 12 | 13 | def monad[A: Arbitrary: Eq, B: Arbitrary: Eq, C: Arbitrary: Eq](implicit 14 | ArbFA: Arbitrary[F[A]], 15 | ArbFB: Arbitrary[F[B]], 16 | ArbFC: Arbitrary[F[C]], 17 | ArbFAtoB: Arbitrary[F[A => B]], 18 | ArbFBtoC: Arbitrary[F[B => C]], 19 | EqFA: Eq[F[A]], 20 | EqFB: Eq[F[B]], 21 | EqFC: Eq[F[C]], 22 | EqFABC: Eq[F[(A, B, C)]], 23 | iso: Isomorphisms[F] 24 | ): RuleSet = { 25 | new RuleSet { 26 | def name: String = "monad" 27 | def bases: Seq[(String, RuleSet)] = Nil 28 | def parents: Seq[RuleSet] = Seq(applicative[A, B, C], flatMap[A, B, C]) 29 | def props: Seq[(String, Prop)] = Seq( 30 | "monad left identity" -> forAll(laws.monadLeftIdentity[A, B] _), 31 | "monad right identity" -> forAll(laws.monadRightIdentity[A] _), 32 | "map flatMap coherence" -> forAll(laws.mapFlatMapCoherence[A, B] _) 33 | ) 34 | } 35 | } 36 | } 37 | 38 | object MonadTests { 39 | def apply[F[_]: Monad]: MonadTests[F] = 40 | new MonadTests[F] { 41 | def laws: MonadLaws[F] = MonadLaws[F] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/MonadWriterTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.laws.discipline.CartesianTests.Isomorphisms 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop.forAll 8 | 9 | trait MonadWriterTests[F[_], W] extends MonadTests[F] { 10 | def laws: MonadWriterLaws[F, W] 11 | 12 | def monadWriter[A: Arbitrary: Eq, B: Arbitrary: Eq, C: Arbitrary: Eq](implicit 13 | ArbFA: Arbitrary[F[A]], 14 | ArbFB: Arbitrary[F[B]], 15 | ArbFC: Arbitrary[F[C]], 16 | ArbFAtoB: Arbitrary[F[A => B]], 17 | ArbFBtoC: Arbitrary[F[B => C]], 18 | EqFA: Eq[F[A]], 19 | EqFAW: Eq[F[(W, A)]], 20 | EqFB: Eq[F[B]], 21 | EqFC: Eq[F[C]], 22 | EqFU: Eq[F[Unit]], 23 | EqFABC: Eq[F[(A, B, C)]], 24 | WA: Arbitrary[W], 25 | WM: Monoid[W], 26 | iso: Isomorphisms[F] 27 | ): RuleSet = 28 | new RuleSet { 29 | def name = "monadWriter" 30 | def bases = Nil 31 | def parents = Seq(monad[A, B, C]) 32 | def props = Seq( 33 | "monadWriter writer pure" -> forAll(laws.monadWriterWriterPure[A] _), 34 | "monadWriter tell fusion" -> forAll(laws.monadWriterTellFusion _), 35 | "monadWriter listen pure" -> forAll(laws.monadWriterListenPure[A] _), 36 | "monadWriter listen writer" -> forAll(laws.monadWriterListenWriter[A] _) 37 | ) 38 | } 39 | } 40 | 41 | object MonadWriterTests { 42 | def apply[F[_], W](implicit FW: MonadWriter[F, W]): MonadWriterTests[F, W] = 43 | new MonadWriterTests[F, W] { 44 | def laws: MonadWriterLaws[F, W] = MonadWriterLaws[F, W] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/MonoidKTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import org.scalacheck.Prop._ 6 | import org.scalacheck.Arbitrary 7 | 8 | trait MonoidKTests[F[_]] extends SemigroupKTests[F] { 9 | def laws: MonoidKLaws[F] 10 | 11 | def monoidK[A: Arbitrary](implicit 12 | ArbFA: Arbitrary[F[A]], 13 | EqFA: Eq[F[A]] 14 | ): RuleSet = 15 | new DefaultRuleSet( 16 | "monoidK", 17 | Some(semigroupK[A]), 18 | "monoidK left identity" -> forAll(laws.monoidKLeftIdentity[A] _), 19 | "monoidK right identity" -> forAll(laws.monoidKRightIdentity[A] _)) 20 | } 21 | 22 | object MonoidKTests { 23 | def apply[F[_] : MonoidK]: MonoidKTests[F] = 24 | new MonoidKTests[F] { def laws: MonoidKLaws[F] = MonoidKLaws[F] } 25 | } 26 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/ProfunctorTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.functor.Profunctor 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop 8 | import Prop._ 9 | import org.typelevel.discipline.Laws 10 | 11 | trait ProfunctorTests[F[_, _]] extends Laws { 12 | def laws: ProfunctorLaws[F] 13 | 14 | def profunctor[A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary, E: Arbitrary, G: Arbitrary](implicit 15 | ArbFAB: Arbitrary[F[A, B]], 16 | ArbFCD: Arbitrary[F[C, D]], 17 | EqFAB: Eq[F[A, B]], 18 | EqFAD: Eq[F[A, D]], 19 | EqFAG: Eq[F[A, G]] 20 | ): RuleSet = 21 | new DefaultRuleSet( 22 | name = "profunctor", 23 | parent = None, 24 | "profunctor identity" -> forAll(laws.profunctorIdentity[A, B] _), 25 | "profunctor composition" -> forAll(laws.profunctorComposition[A, B, C, D, E, G] _), 26 | "profunctor lmap identity" -> forAll(laws.profunctorLmapIdentity[A, B] _), 27 | "profunctor rmap identity" -> forAll(laws.profunctorRmapIdentity[A, B] _), 28 | "profunctor lmap composition" -> forAll(laws.profunctorLmapComposition[A, B, C, D] _), 29 | "profunctor rmap composition" -> forAll(laws.profunctorRmapComposition[A, D, C, B] _)) 30 | } 31 | 32 | object ProfunctorTests { 33 | def apply[F[_, _]: Profunctor]: ProfunctorTests[F] = 34 | new ProfunctorTests[F] { def laws: ProfunctorLaws[F] = ProfunctorLaws[F] } 35 | } 36 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/ReducibleTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import org.scalacheck.Arbitrary 6 | import org.scalacheck.Prop.forAll 7 | 8 | trait ReducibleTests[F[_]] extends FoldableTests[F] { 9 | def laws: ReducibleLaws[F] 10 | 11 | def reducible[G[_]: Applicative, A: Arbitrary, B: Arbitrary](implicit 12 | ArbFA: Arbitrary[F[A]], 13 | ArbFGA: Arbitrary[F[G[A]]], 14 | ArbGB: Arbitrary[G[B]], 15 | B: Monoid[B], 16 | EqG: Eq[G[Unit]], 17 | EqB: Eq[B] 18 | ): RuleSet = 19 | new DefaultRuleSet( 20 | name = "reducible", 21 | parent = Some(foldable[A, B]), 22 | "reduceLeftTo consistent with reduceMap" -> forAll(laws.reduceLeftToConsistentWithReduceMap[A, B] _), 23 | "reduceRightTo consistent with reduceMap" -> forAll(laws.reduceRightToConsistentWithReduceMap[A, B] _), 24 | "traverse1_ consistent with traverse_" -> forAll(laws.traverseConsistent[G, A, B] _), 25 | "sequence1_ consistent with sequence_" -> forAll(laws.sequenceConsistent[G, A] _) 26 | ) 27 | } 28 | 29 | object ReducibleTests { 30 | def apply[F[_] : Reducible]: ReducibleTests[F] = 31 | new ReducibleTests[F] { def laws: ReducibleLaws[F] = ReducibleLaws[F] } 32 | } 33 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/SemigroupKTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import org.scalacheck.Prop._ 6 | import org.scalacheck.Arbitrary 7 | import org.typelevel.discipline.Laws 8 | 9 | trait SemigroupKTests[F[_]] extends Laws { 10 | def laws: SemigroupKLaws[F] 11 | 12 | def semigroupK[A: Arbitrary](implicit 13 | ArbFA: Arbitrary[F[A]], 14 | EqFA: Eq[F[A]] 15 | ): RuleSet = 16 | new DefaultRuleSet( 17 | "semigroupK", 18 | None, 19 | "semigroupK associative" -> forAll(laws.semigroupKAssociative[A] _)) 20 | } 21 | 22 | object SemigroupKTests { 23 | def apply[F[_]: SemigroupK]: SemigroupKTests[F] = 24 | new SemigroupKTests[F] { def laws: SemigroupKLaws[F] = SemigroupKLaws[F] } 25 | } 26 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/SerializableTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import org.typelevel.discipline.Laws 6 | 7 | object SerializableTests extends Laws { 8 | def serializable[A](a: A): RuleSet = 9 | new DefaultRuleSet( 10 | name = "serializable", 11 | parent = None, 12 | "can serialize and deserialize" -> SerializableLaws.serializable(a)) 13 | } 14 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/SplitTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.arrow.Split 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop 8 | import Prop._ 9 | 10 | trait SplitTests[F[_, _]] extends ComposeTests[F] { 11 | def laws: SplitLaws[F] 12 | 13 | def split[A, B, C, D, E, G](implicit 14 | ArbFAB: Arbitrary[F[A, B]], 15 | ArbFBC: Arbitrary[F[B, C]], 16 | ArbFCD: Arbitrary[F[C, D]], 17 | ArbFDE: Arbitrary[F[D, E]], 18 | ArbFEG: Arbitrary[F[E, G]], 19 | EqFAD: Eq[F[A, D]], 20 | EqFADCG: Eq[F[(A, D), (C, G)]] 21 | ): RuleSet = 22 | new DefaultRuleSet( 23 | name = "split", 24 | parent = Some(compose[A, B, C, D]), 25 | "split interchange" -> forAll(laws.splitInterchange[A, B, C, D, E, G] _)) 26 | } 27 | 28 | object SplitTests { 29 | def apply[F[_, _]: Split]: SplitTests[F] = 30 | new SplitTests[F] { def laws: SplitLaws[F] = SplitLaws[F] } 31 | } 32 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/StrongTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import cats.functor.Strong 6 | import org.scalacheck.Arbitrary 7 | import org.scalacheck.Prop 8 | import Prop._ 9 | 10 | trait StrongTests[F[_, _]] extends ProfunctorTests[F] { 11 | def laws: StrongLaws[F] 12 | 13 | def strong[A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary, E: Arbitrary, G: Arbitrary](implicit 14 | ArbFAB: Arbitrary[F[A, B]], 15 | ArbFBC: Arbitrary[F[B, C]], 16 | ArbFCD: Arbitrary[F[C, D]], 17 | EqFAB: Eq[F[A, B]], 18 | EqFAD: Eq[F[A, D]], 19 | EqFAG: Eq[F[A, G]], 20 | EqFAEDE: Eq[F[(A, E), (D, E)]], 21 | EqFEAED: Eq[F[(E, A), (E, D)]] 22 | ): RuleSet = 23 | new DefaultRuleSet( 24 | name = "strong", 25 | parent = Some(profunctor[A, B, C, D, E, G]), 26 | "strong first distributivity" -> forAll(laws.strongFirstDistributivity[A, B, C, D, E] _), 27 | "strong second distributivity" -> forAll(laws.strongSecondDistributivity[A, B, C, D, E] _)) 28 | } 29 | 30 | object StrongTests { 31 | def apply[F[_, _]: Strong]: StrongTests[F] = 32 | new StrongTests[F] { def laws: StrongLaws[F] = StrongLaws[F] } 33 | } 34 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | package discipline 4 | 5 | import org.scalacheck.{Prop, Arbitrary} 6 | import Prop._ 7 | 8 | trait TraverseFilterTests[F[_]] extends TraverseTests[F] with FunctorFilterTests[F] { 9 | def laws: TraverseFilterLaws[F] 10 | 11 | def traverseFilter[A: Arbitrary, B: Arbitrary, C: Arbitrary, M: Arbitrary, X[_]: Applicative, Y[_]: Applicative](implicit 12 | ArbFA: Arbitrary[F[A]], 13 | ArbXB: Arbitrary[X[B]], 14 | ArbYB: Arbitrary[Y[B]], 15 | ArbYC: Arbitrary[Y[C]], 16 | ArbAXOB: Arbitrary[A => X[Option[B]]], 17 | ArbBYOC: Arbitrary[B => Y[Option[C]]], 18 | M: Monoid[M], 19 | EqFA: Eq[F[A]], 20 | EqFC: Eq[F[C]], 21 | EqM: Eq[M], 22 | EqXYFC: Eq[X[Y[F[C]]]], 23 | EqXFA: Eq[X[F[A]]], 24 | EqXFB: Eq[X[F[B]]], 25 | EqYFB: Eq[Y[F[B]]] 26 | ): RuleSet = { 27 | new RuleSet { 28 | def name: String = "traverseFilter" 29 | def bases: Seq[(String, RuleSet)] = Nil 30 | def parents: Seq[RuleSet] = Seq(traverse[A, B, C, M, X, Y], functorFilter[A, B, C]) 31 | def props: Seq[(String, Prop)] = Seq( 32 | "traverseFilter identity" -> forAll(laws.traverseFilterIdentity[X, A] _), 33 | "traverseFilter composition" -> forAll(laws.traverseFilterComposition[A, B, C, X, Y] _) 34 | ) 35 | } 36 | } 37 | } 38 | 39 | object TraverseFilterTests { 40 | def apply[F[_]: TraverseFilter]: TraverseFilterTests[F] = 41 | new TraverseFilterTests[F] { def laws: TraverseFilterLaws[F] = TraverseFilterLaws[F] } 42 | } 43 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/discipline/package.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package laws 3 | 4 | import cats.kernel.laws._ 5 | 6 | import org.scalacheck.Prop 7 | 8 | package object discipline { 9 | implicit def catsLawsIsEqToProp[A: Eq](isEq: IsEq[A]): Prop = 10 | isEq.lhs ?== isEq.rhs 11 | } 12 | -------------------------------------------------------------------------------- /laws/src/main/scala/cats/laws/package.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | package object laws { 4 | implicit final class IsEqArrow[A](val lhs: A) extends AnyVal { 5 | def <->(rhs: A): IsEq[A] = IsEq(lhs, rhs) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /macros/src/main/scala/cats/macros/Ops.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package macros 3 | 4 | import scala.reflect.NameTransformer 5 | 6 | object Ops extends machinist.Ops { 7 | 8 | def uesc(c: Char): String = "$u%04X".format(c.toInt) 9 | 10 | val operatorNames: Map[String, String] = 11 | List( 12 | ("===", "eqv"), 13 | ("=!=", "neqv"), 14 | (">", "gt"), 15 | (">=", "gteqv"), 16 | ("<", "lt"), 17 | ("<=", "lteqv"), 18 | ("|+|", "combine"), 19 | ("|-|", "remove") 20 | ).map{ case (k, v) => 21 | (NameTransformer.encode(k), v) 22 | }.toMap 23 | } 24 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.12 2 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.eed3si9n" % "sbt-unidoc" % "0.3.3") 2 | addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.3") 3 | addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") 4 | addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.1.9") 5 | addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.5.3") 6 | addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "0.8.1") 7 | addSbtPlugin("org.tpolecat" % "tut-plugin" % "0.4.3") 8 | addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.2.11") 9 | addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "0.8.0") 10 | addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.2.0") 11 | addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "0.8.5") 12 | addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.11") 13 | addSbtPlugin("com.github.tkawachi" % "sbt-doctest" % "0.4.1") 14 | addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "1.1") 15 | -------------------------------------------------------------------------------- /scripts/sbtrc-JVM: -------------------------------------------------------------------------------- 1 | alias boot = ;reload ;project coreJVM ;iflast shell -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/ApplicativeErrorTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.data.EitherT 5 | 6 | class ApplicativeErrorCheck extends CatsSuite { 7 | val failed: Option[Int] = 8 | (()).raiseError[Option, Int] 9 | 10 | test("raiseError syntax creates an Option with the correct value") { 11 | failed should === (None: Option[Int]) 12 | } 13 | 14 | test("handleError syntax transforms an error to a success") { 15 | failed.handleError(_ => 7) should === (Some(7)) 16 | } 17 | 18 | test("handleErrorWith transforms an error to a success") { 19 | failed.handleErrorWith(_ => Some(7)) should === (Some(7)) 20 | } 21 | 22 | test("attempt syntax creates a wrapped Either") { 23 | failed.attempt should === (Option(Left(()))) 24 | } 25 | 26 | test("attemptT syntax creates an EitherT") { 27 | failed.attemptT should === (EitherT[Option, Unit, Int](Option(Left(())))) 28 | } 29 | 30 | test("recover syntax transforms an error to a success") { 31 | failed.recover { case _ => 7 } should === (Some(7)) 32 | } 33 | 34 | test("recoverWith transforms an error to a success") { 35 | failed.recoverWith { case _ => Some(7) } should === (Some(7)) 36 | } 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/ApplicativeTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.Applicative 5 | 6 | 7 | class ApplicativeCheck extends CatsSuite { 8 | 9 | test("replicateA creates a List of 'n' copies of given Applicative 'fa'") { 10 | 11 | val A = Applicative[Option] 12 | val fa = A.pure(1) 13 | A.replicateA(5, fa) should === (Some(List(1,1,1,1,1))) 14 | 15 | } 16 | } -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/BifoldableTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.laws.discipline.{BifoldableTests, SerializableTests} 5 | 6 | class BifoldableTest extends CatsSuite { 7 | type EitherEither[A, B] = Either[Either[A, B], Either[A, B]] 8 | val eitherComposeEither: Bifoldable[EitherEither] = 9 | Bifoldable[Either].compose[Either] 10 | 11 | checkAll("Either compose Either", BifoldableTests(eitherComposeEither).bifoldable[Int, Int, Int]) 12 | checkAll("Bifoldable[Either compose Either]", SerializableTests.serializable(eitherComposeEither)) 13 | } 14 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/BifunctorTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.functor.Bifunctor 5 | import cats.laws.discipline.{SerializableTests, BifunctorTests} 6 | 7 | class BifunctorTest extends CatsSuite { 8 | type Tuple2Either[A, B] = (Either[A, B], Either[A, B]) 9 | val tuple2ComposeEither: Bifunctor[Tuple2Either] = 10 | Bifunctor[Tuple2].compose[Either] 11 | 12 | checkAll("Tuple2 compose Either", BifunctorTests(tuple2ComposeEither).bifunctor[Int, Int, Int, String, String, String]) 13 | checkAll("Bifunctor[Tuple2 compose Either]", SerializableTests.serializable(tuple2ComposeEither)) 14 | } 15 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/BitraverseTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.laws.discipline.{BitraverseTests, SerializableTests} 5 | 6 | class BitraverseTest extends CatsSuite { 7 | type EitherTuple2[A, B] = Either[(A, B), (A, B)] 8 | val eitherComposeTuple2: Bitraverse[EitherTuple2] = 9 | Bitraverse[Either].compose[Tuple2] 10 | 11 | checkAll("Either compose Tuple2", BitraverseTests(eitherComposeTuple2).bitraverse[Option, Int, Int, Int, String, String, String]) 12 | checkAll("Bitraverse[Either compose Tuple2]", SerializableTests.serializable(eitherComposeTuple2)) 13 | } 14 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/CategoryTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.kernel.laws.GroupLaws 5 | 6 | import cats.arrow.Category 7 | import cats.laws.discipline.{MonoidKTests, SerializableTests} 8 | import cats.laws.discipline.eq.catsLawsEqForFn1 9 | 10 | class CategoryTest extends CatsSuite { 11 | val functionCategory = Category[Function1] 12 | type Endo[A] = Function1[A, A] 13 | 14 | checkAll("Category[Function1].algebraK", MonoidKTests[Endo](functionCategory.algebraK).monoidK[Int]) 15 | checkAll("Category[Function1].algebraK", SerializableTests.serializable(functionCategory.algebraK)) 16 | 17 | val functionAlgebra = functionCategory.algebra[Int] 18 | checkAll("Category[Function1].algebra[Int]", GroupLaws[Endo[Int]].monoid(functionAlgebra)) 19 | } 20 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/CatsEquality.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import org.scalactic._ 5 | import TripleEqualsSupport.AToBEquivalenceConstraint 6 | import TripleEqualsSupport.BToAEquivalenceConstraint 7 | 8 | // The code in this file was taken and only slightly modified from 9 | // https://github.com/bvenners/equality-integration-demo 10 | // Thanks for the great examples, Bill! 11 | 12 | final class CatsEquivalence[T](T: Eq[T]) extends Equivalence[T] { 13 | def areEquivalent(a: T, b: T): Boolean = T.eqv(a, b) 14 | } 15 | 16 | trait LowPriorityStrictCatsConstraints extends TripleEquals { 17 | implicit def lowPriorityCatsCanEqual[A, B](implicit B: Eq[B], ev: A <:< B): CanEqual[A, B] = 18 | new AToBEquivalenceConstraint[A, B](new CatsEquivalence(B), ev) 19 | } 20 | 21 | trait StrictCatsEquality extends LowPriorityStrictCatsConstraints { 22 | override def convertToEqualizer[T](left: T): Equalizer[T] = super.convertToEqualizer[T](left) 23 | implicit override def convertToCheckingEqualizer[T](left: T): CheckingEqualizer[T] = new CheckingEqualizer(left) 24 | override def unconstrainedEquality[A, B](implicit equalityOfA: Equality[A]): CanEqual[A, B] = super.unconstrainedEquality[A, B] 25 | implicit def catsCanEqual[A, B](implicit A: Eq[A], ev: B <:< A): CanEqual[A, B] = 26 | new BToAEquivalenceConstraint[A, B](new CatsEquivalence(A), ev) 27 | } 28 | 29 | object StrictCatsEquality extends StrictCatsEquality 30 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/ComposeTest.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.kernel.laws.GroupLaws 5 | 6 | import cats.arrow.Compose 7 | import cats.laws.discipline.{SemigroupKTests, SerializableTests} 8 | import cats.laws.discipline.eq.catsLawsEqForFn1 9 | 10 | class ComposeTest extends CatsSuite { 11 | val functionCompose = Compose[Function1] 12 | type Endo[A] = Function1[A, A] 13 | 14 | checkAll("Compose[Function1].algebraK", SemigroupKTests[Endo](functionCompose.algebraK).semigroupK[Int]) 15 | checkAll("Compose[Function1].algebraK", SerializableTests.serializable(functionCompose.algebraK)) 16 | 17 | val functionAlgebra = functionCompose.algebra[Int] 18 | checkAll("Compose[Function1].algebra[Int]", GroupLaws[Endo[Int]].semigroup(functionAlgebra)) 19 | } 20 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/ContravariantTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.data.Const 5 | import org.scalactic.CanEqual 6 | 7 | class ContravariantTest extends CatsSuite { 8 | 9 | test("narrow equals contramap(identity)") { 10 | implicit val constInst = Const.catsDataContravariantForConst[Int] 11 | implicit val canEqual: CanEqual[cats.data.Const[Int,Some[Int]],cats.data.Const[Int,Some[Int]]] = 12 | StrictCatsEquality.lowPriorityConversionCheckedConstraint 13 | forAll { (i: Int) => 14 | val const: Const[Int, Option[Int]] = Const[Int, Option[Int]](i) 15 | val narrowed: Const[Int, Some[Int]] = constInst.narrow[Option[Int], Some[Int]](const) 16 | narrowed should === (constInst.contramap(const)(identity[Option[Int]](_: Some[Int]))) 17 | assert(narrowed eq const) 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/FunctorTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | class FunctorTest extends CatsSuite { 5 | test("void replaces values with unit preserving structure") { 6 | forAll { (l: List[Int], o: Option[Int], m: Map[String, Int]) => 7 | l.void should === (List.fill(l.length)(())) 8 | o.void should === (if (o.nonEmpty) Some(()) else None) 9 | m.void should === (m.keys.map(k => (k, ())).toMap) 10 | } 11 | } 12 | 13 | test("as replaces values with a constant value preserving structure") { 14 | forAll { (l: List[Int], o: Option[Int], m: Map[String, Int], i: Int) => 15 | l.as(i) should === (List.fill(l.length)(i)) 16 | o.as(i) should === (if (o.nonEmpty) Some(i) else None) 17 | m.as(i) should === (m.keys.map(k => (k, i)).toMap) 18 | } 19 | } 20 | 21 | test("widen equals map(identity)") { 22 | forAll { (i: Int) => 23 | val list: List[Some[Int]] = List(Some(i)) 24 | val widened: List[Option[Int]] = list.widen[Option[Int]] 25 | widened should === (list.map(identity[Option[Int]])) 26 | assert(widened eq list) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/IdTTests.scala: -------------------------------------------------------------------------------- 1 | package cats.tests 2 | 3 | import cats.{Foldable, Functor, Monad, Traverse} 4 | import cats.data.IdT 5 | import cats.laws.discipline.{CartesianTests, FoldableTests, FunctorTests, MonadTests, SerializableTests, TraverseTests} 6 | import cats.laws.discipline.arbitrary._ 7 | 8 | class IdTTests extends CatsSuite { 9 | 10 | implicit val iso = CartesianTests.Isomorphisms.invariant[IdT[List, ?]] 11 | 12 | checkAll("IdT[Functor, Int]", FunctorTests[IdT[List, ?]].functor[Int, Int, Int]) 13 | checkAll("Functor[IdT[List, ?]]", SerializableTests.serializable(Functor[IdT[List, ?]])) 14 | 15 | checkAll("IdT[List, Int]", MonadTests[IdT[List, ?]].monad[Int, Int, Int]) 16 | checkAll("Monad[IdT[List, ?]]", SerializableTests.serializable(Monad[IdT[List, ?]])) 17 | 18 | checkAll("IdT[Option, Int]", FoldableTests[IdT[Option, ?]].foldable[Int, Int]) 19 | checkAll("Foldable[IdT[Option, ?]]", SerializableTests.serializable(Foldable[IdT[Option, ?]])) 20 | 21 | checkAll("IdT[Option, Int]", TraverseTests[IdT[Option, ?]].traverse[Int, Int, Int, Int, Option, Option]) 22 | checkAll("Traverse[IdT[Option, ?]]", SerializableTests.serializable(Traverse[IdT[Option, ?]])) 23 | 24 | } 25 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/IdTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.laws.discipline._ 5 | 6 | class IdTests extends CatsSuite { 7 | implicit val iso = CartesianTests.Isomorphisms.invariant[Id] 8 | 9 | checkAll("Id[Int]", BimonadTests[Id].bimonad[Int, Int, Int]) 10 | checkAll("Bimonad[Id]", SerializableTests.serializable(Bimonad[Id])) 11 | 12 | checkAll("Id[Int]", MonadTests[Id].monad[Int, Int, Int]) 13 | checkAll("Monad[Id]", SerializableTests.serializable(Monad[Id])) 14 | 15 | checkAll("Id[Int]", TraverseTests[Id].traverse[Int, Int, Int, Int, Option, Option]) 16 | checkAll("Traverse[Id]", SerializableTests.serializable(Traverse[Id])) 17 | } 18 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/KernelContravariantTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.functor.Contravariant 5 | import cats.laws.discipline.arbitrary._ 6 | import cats.laws.discipline.{ContravariantTests, SerializableTests} 7 | import cats.laws.discipline.eq._ 8 | 9 | class KernelContravariantTests extends CatsSuite { 10 | checkAll("Contravariant[Eq]", ContravariantTests[Eq].contravariant[Int, Int, Int]) 11 | checkAll("Contravariant[Eq]", SerializableTests.serializable(Contravariant[Eq])) 12 | 13 | checkAll("Contravariant[PartialOrder]", ContravariantTests[PartialOrder].contravariant[Int, Int, Int]) 14 | checkAll("Contravariant[PartialOrder]", SerializableTests.serializable(Contravariant[PartialOrder])) 15 | 16 | checkAll("Contravariant[Order]", ContravariantTests[Order].contravariant[Int, Int, Int]) 17 | checkAll("Contravariant[Order]", SerializableTests.serializable(Contravariant[Order])) 18 | } 19 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/ListTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.data.NonEmptyList 5 | import cats.laws.discipline.{TraverseFilterTests, CoflatMapTests, MonadCombineTests, SerializableTests, CartesianTests} 6 | import cats.laws.discipline.arbitrary._ 7 | 8 | class ListTests extends CatsSuite { 9 | 10 | checkAll("List[Int]", CartesianTests[List].cartesian[Int, Int, Int]) 11 | checkAll("Cartesian[List]", SerializableTests.serializable(Cartesian[List])) 12 | 13 | checkAll("List[Int]", CoflatMapTests[List].coflatMap[Int, Int, Int]) 14 | checkAll("CoflatMap[List]", SerializableTests.serializable(CoflatMap[List])) 15 | 16 | checkAll("List[Int]", MonadCombineTests[List].monadCombine[Int, Int, Int]) 17 | checkAll("MonadCombine[List]", SerializableTests.serializable(MonadCombine[List])) 18 | 19 | checkAll("List[Int] with Option", TraverseFilterTests[List].traverseFilter[Int, Int, Int, List[Int], Option, Option]) 20 | checkAll("TraverseFilter[List]", SerializableTests.serializable(TraverseFilter[List])) 21 | 22 | test("nel => list => nel returns original nel")( 23 | forAll { fa: NonEmptyList[Int] => 24 | fa.toList.toNel should === (Some(fa)) 25 | } 26 | ) 27 | 28 | test("toNel on empty list returns None"){ 29 | List.empty[Int].toNel should === (None) 30 | } 31 | 32 | test("show"){ 33 | List(1, 2, 3).show should === ("List(1, 2, 3)") 34 | (Nil: List[Int]).show should === ("List()") 35 | forAll { l: List[String] => 36 | l.show should === (l.toString) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/MapTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.laws.discipline.{TraverseFilterTests, FlatMapTests, SerializableTests, CartesianTests} 5 | 6 | class MapTests extends CatsSuite { 7 | implicit val iso = CartesianTests.Isomorphisms.invariant[Map[Int, ?]] 8 | 9 | checkAll("Map[Int, Int]", CartesianTests[Map[Int, ?]].cartesian[Int, Int, Int]) 10 | checkAll("Cartesian[Map[Int, ?]]", SerializableTests.serializable(Cartesian[Map[Int, ?]])) 11 | 12 | checkAll("Map[Int, Int]", FlatMapTests[Map[Int, ?]].flatMap[Int, Int, Int]) 13 | checkAll("FlatMap[Map[Int, ?]]", SerializableTests.serializable(FlatMap[Map[Int, ?]])) 14 | 15 | checkAll("Map[Int, Int] with Option", TraverseFilterTests[Map[Int, ?]].traverseFilter[Int, Int, Int, Int, Option, Option]) 16 | checkAll("TraverseFilter[Map[Int, ?]]", SerializableTests.serializable(TraverseFilter[Map[Int, ?]])) 17 | 18 | test("show isn't empty and is formatted as expected") { 19 | forAll { (map: Map[Int, String]) => 20 | map.show.nonEmpty should === (true) 21 | map.show.startsWith("Map(") should === (true) 22 | map.show should === (implicitly[Show[Map[Int, String]]].show(map)) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/MonadCombineTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | class MonadCombineTest extends CatsSuite { 5 | test("separate") { 6 | forAll { (list: List[Either[Int, String]]) => 7 | val ints = list.collect { case Left(i) => i } 8 | val strings = list.collect { case Right(s) => s } 9 | val expected = (ints, strings) 10 | 11 | MonadCombine[List].separate(list) should === (expected) 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/MonadErrorSuite.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | class MonadErrorSuite extends CatsSuite { 5 | 6 | val successful: Option[Int] = 42.some 7 | val failed: Option[Int] = None 8 | 9 | test("ensure raises an error if the predicate fails") { 10 | successful.ensure(())(i => false) should === (None) 11 | } 12 | 13 | test("ensure returns the successful value if the predicate succeeds") { 14 | successful.ensure(())(i => true) should === (successful) 15 | } 16 | 17 | test("ensure returns the failure, when applied to a failure") { 18 | failed.ensure(())(i => false) should === (failed) 19 | failed.ensure(())(i => true) should === (failed) 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/MonadStateTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.data.State 5 | 6 | class MonadStateTest extends CatsSuite { 7 | val testInstance = MonadState[State[Int, ?], Int] 8 | 9 | test("MonadState#modify identity does not modify the state") { 10 | forAll { (i: Int) => 11 | val x = testInstance.modify(identity).runS(i).value 12 | x should === (i) 13 | } 14 | } 15 | 16 | test("MonadState#inspect identity does not modify the state") { 17 | forAll { (i: Int) => 18 | val x = testInstance.inspect(identity).runA(i).value 19 | x should === (i) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/ReducibleTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import org.scalacheck.Arbitrary 5 | 6 | class ReducibleTestsAdditional extends CatsSuite { 7 | 8 | test("Reducible[NonEmptyList].reduceLeftM stack safety") { 9 | def nonzero(acc: Long, x: Long): Option[Long] = 10 | if (x == 0) None else Some(acc + x) 11 | 12 | val n = 100000L 13 | val expected = n*(n+1)/2 14 | val actual = (1L to n).toList.toNel.flatMap(_.reduceLeftM(Option.apply)(nonzero)) 15 | actual should === (Some(expected)) 16 | } 17 | 18 | } 19 | 20 | abstract class ReducibleCheck[F[_]: Reducible](name: String)(implicit ArbFInt: Arbitrary[F[Int]]) extends FoldableCheck[F](name) { 21 | def range(start: Long, endInclusive: Long): F[Long] 22 | 23 | test(s"Reducible[$name].reduceLeftM stack safety") { 24 | def nonzero(acc: Long, x: Long): Option[Long] = 25 | if (x == 0) None else Some(acc + x) 26 | 27 | val n = 100000L 28 | val expected = n*(n+1)/2 29 | val actual = range(1L, n).reduceLeftM(Option.apply)(nonzero) 30 | actual should === (Some(expected)) 31 | } 32 | 33 | test(s"Reducible[$name].toNonEmptyList/toList consistency") { 34 | forAll { fa: F[Int] => 35 | fa.toList.toNel should === (Some(fa.toNonEmptyList)) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/SetTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.laws.discipline.{FoldableTests, MonoidKTests, SerializableTests} 5 | 6 | class SetTests extends CatsSuite { 7 | checkAll("Set[Int]", cats.kernel.laws.GroupLaws[Set[Int]].monoid) 8 | 9 | checkAll("Set[Int]", MonoidKTests[Set].monoidK[Int]) 10 | checkAll("MonoidK[Set]", SerializableTests.serializable(MonoidK[Set])) 11 | 12 | checkAll("Set[Int]", FoldableTests[Set].foldable[Int, Int]) 13 | checkAll("Foldable[Set]", SerializableTests.serializable(Foldable[Set])) 14 | 15 | test("show"){ 16 | Set(1, 1, 2, 3).show should === ("Set(1, 2, 3)") 17 | Set.empty[String].show should === ("Set()") 18 | 19 | forAll { fs: Set[String] => 20 | fs.show should === (fs.toString) 21 | } 22 | } 23 | 24 | test("show keeps separate entries for items that map to identical strings"){ 25 | //note: this val name has to be the same to shadow the cats.instances instance 26 | implicit val catsStdShowForInt: Show[Int] = Show.show(_ => "1") 27 | // an implementation implemented as set.map(_.show).mkString(", ") would 28 | // only show one entry in the result instead of 3, because Set.map combines 29 | // duplicate items in the codomain. 30 | Set(1, 2, 3).show should === ("Set(1, 1, 1)") 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/ShowTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.functor.Contravariant 5 | import cats.laws.discipline.arbitrary._ 6 | import cats.laws.discipline.{ContravariantTests, SerializableTests} 7 | import cats.laws.discipline.eq._ 8 | 9 | class ShowTests extends CatsSuite { 10 | checkAll("Contravariant[Show]", ContravariantTests[Show].contravariant[Int, Int, Int]) 11 | checkAll("Contravariant[Show]", SerializableTests.serializable(Contravariant[Show])) 12 | } 13 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/TransLiftTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.data.{EitherT, OptionT, WriterT, Kleisli, StateT} 5 | 6 | class TransLiftTests extends CatsSuite { 7 | 8 | case class NoTypeclass[A](a: A) 9 | 10 | case class JustFunctor[A](a: A) 11 | 12 | implicit val jfFunctor: Functor[JustFunctor] = new Functor[JustFunctor] { 13 | override def map[A, B](fa: JustFunctor[A])(f: A => B): JustFunctor[B] = JustFunctor(f(fa.a)) 14 | } 15 | 16 | case class JustAp[A](a: A) 17 | 18 | implicit val jfApp: Applicative[JustAp] = new Applicative[JustAp] { 19 | override def pure[A](a: A): JustAp[A] = JustAp(a) 20 | override def ap[A, B](ff: JustAp[A => B])(fa: JustAp[A]): JustAp[B] = JustAp(ff.a(fa.a)) 21 | override def product[A, B](fa: JustAp[A],fb: JustAp[B]): JustAp[(A, B)] = JustAp(fa.a -> fb.a) 22 | override def map[A, B](fa: JustAp[A])(f: A => B): JustAp[B] = JustAp(f(fa.a)) 23 | } 24 | 25 | test("transLift for EitherT, OptionT, WriterT requires only Functor") { 26 | val e: EitherT[JustFunctor, Int, Int] = JustFunctor(1).liftT[λ[(α[_], β) => EitherT[α, Int, β]]] 27 | val c: OptionT[JustFunctor, Int] = JustFunctor(1).liftT[OptionT] 28 | val a: WriterT[JustFunctor, Int, Int] = JustFunctor(1).liftT[λ[(α[_], β) => WriterT[α, Int, β]]] 29 | } 30 | 31 | test("transLift for StateT requires Applicative Functor") { 32 | val f: StateT[JustAp, Int, Int] = JustAp(1).liftT[λ[(α[_], β) => StateT[α, Int, β]]] 33 | } 34 | 35 | test("transLift for Kleisli doesn't require anything of the wrapped value"){ 36 | val e: Kleisli[NoTypeclass, Int, Int] = NoTypeclass(1).liftT[λ[(α[_], β) => Kleisli[α, Int, β]]] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/UnapplyTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.data._ 5 | import cats.laws.discipline.SerializableTests 6 | 7 | // the things we assert here are not so much important, what is 8 | // important is that this stuff compiles at all. 9 | class UnapplyTests extends CatsSuite { 10 | 11 | test("Unapply works for stuff already the right kind") { 12 | val x = Traverse[List].traverseU(List(1,2,3))(Option(_)) 13 | x should === (Some(List(1,2,3))) 14 | } 15 | 16 | test("Unapply works for F[_,_] with the left fixed") { 17 | val x = Traverse[List].traverseU(List(1,2,3))(Either.right(_)) 18 | (x: Either[String, List[Int]]) should === (Either.right(List(1,2,3))) 19 | } 20 | 21 | test("Unapply works for F[_[_],_] with the left fixed") { 22 | val x: OptionT[List, Int] = OptionT(List(Option(1), Option(2))) 23 | val y: OptionT[List, Int] = OptionT(List(Option(3), Option(4))) 24 | 25 | val z: List[Option[(Int,Int)]] = (x |@| y).tupled.value 26 | 27 | z should be (List(Option((1,3)), Option((1,4)), 28 | Option((2,3)), Option((2,4)))) 29 | } 30 | 31 | checkAll("Unapply[Functor, Option[String]]", SerializableTests.serializable(Unapply[Functor, Option[String]])) 32 | 33 | test("Unapply works for F[_[_], _[_], _]") { 34 | val x: List[Option[Int]] = List(Option(1), Option(2)) 35 | val y: Nested[List, Option, Int] = Nested(x) 36 | 37 | y.map(_ + 1).value should === (x.map(_.map(_ + 1))) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/VectorTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.laws.discipline.{MonadCombineTests, CoflatMapTests, SerializableTests, TraverseFilterTests, CartesianTests} 5 | 6 | class VectorTests extends CatsSuite { 7 | checkAll("Vector[Int]", CartesianTests[Vector].cartesian[Int, Int, Int]) 8 | checkAll("Cartesian[Vector]", SerializableTests.serializable(Cartesian[Vector])) 9 | 10 | checkAll("Vector[Int]", CoflatMapTests[Vector].coflatMap[Int, Int, Int]) 11 | checkAll("CoflatMap[Vector]", SerializableTests.serializable(CoflatMap[Vector])) 12 | 13 | checkAll("Vector[Int]", MonadCombineTests[Vector].monadCombine[Int, Int, Int]) 14 | checkAll("MonadCombine[Vector]", SerializableTests.serializable(MonadCombine[Vector])) 15 | 16 | checkAll("Vector[Int] with Option", TraverseFilterTests[Vector].traverseFilter[Int, Int, Int, List[Int], Option, Option]) 17 | checkAll("TraverseFilter[Vector]", SerializableTests.serializable(TraverseFilter[Vector])) 18 | 19 | test("show") { 20 | Vector(1, 2, 3).show should === ("Vector(1, 2, 3)") 21 | 22 | Vector.empty[Int].show should === ("Vector()") 23 | 24 | forAll { vec: Vector[String] => 25 | vec.show should === (vec.toString) 26 | } 27 | } 28 | 29 | test("collect consistency") { 30 | forAll { vec: Vector[Int] => 31 | FunctorFilter[Vector].collect(vec)(evenPf) should === (vec.collect(evenPf)) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/src/test/scala/cats/tests/WriterTests.scala: -------------------------------------------------------------------------------- 1 | package cats 2 | package tests 3 | 4 | import cats.data.Writer 5 | 6 | class WriterTests extends CatsSuite { 7 | test("pure syntax creates a writer with an empty log"){ 8 | forAll { (result: String) => 9 | type Logged[A] = Writer[List[Int], A] 10 | result.pure[Logged] should === (Writer(List.empty[Int], result)) 11 | } 12 | } 13 | 14 | test("tell syntax creates a writer with a unit result"){ 15 | forAll { (log: List[Int]) => 16 | log.tell should === (Writer(log, ())) 17 | } 18 | } 19 | 20 | test("writer syntax creates a writer with the specified result and log") { 21 | forAll { (result: String, log: List[Int]) => 22 | result.writer(log) should === (Writer(log, result)) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /version.sbt: -------------------------------------------------------------------------------- 1 | version in ThisBuild := "0.7.2-SNAPSHOT" 2 | --------------------------------------------------------------------------------