cats Documentation

Lightweight, modular, and extensible library for functional programming.

5,475 stars Scala Scala 65 files · ~125,608 tokens
RAW Doc

Technical Documentation: typelevel/cats

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (`README.md`)

Cats



Overview

Cats is a library which provides abstractions for functional programming in the Scala programming language.

Scala supports both object-oriented and functional programming, and this is reflected in the hybrid approach of the
standard library. Cats strives to provide functional programming abstractions that are core, binary compatible, modular, approachable and efficient. A broader goal of Cats is to provide a foundation for an ecosystem of pure, typeful libraries to support functional programming in Scala applications.

For more detail about Cats' motivations, go here.

Why "cats"?

The name is a playful shortening of the word category, from "category theory".

Regardless, you do not need to know anything about category theory to use Cats.

Contributors

Code Contributors

This project exists thanks to all the people who contribute. We welcome contributions to Cats and would love for you to help build
Cats. See our contributor guide for more
information about how you can get involved as a developer. If you are looking for something to start with, here is a beginner friendly list.

Financial Contributors

Become a financial contributor and help us sustain our community. Donations directly support office hours for maintainers, better documentation and strategic initiatives.

Platinum Sponsors

[Platinum sponsorship](https://opencollective.com/typelevel/contribute/platinum-sposor-12420/checkout) starts at $950 USD/month.

Gold Sponsors

[Gold Sponsorship](https://opencollective.com/typelevel/contribute/gold-sponsor-12419/checkout) starts at $420 USD/month.

Silver Sponsors

[Silver Sponsorship](https://opencollective.com/typelevel/contribute/silver-sponsor-11780/checkout) starts at $180 USD/month.

Backers

Become a [Backer](https://opencollective.com/typelevel/contribute/backer-11779/checkout) with a recurring donation of just $5 USD/month.

Other contributors

We thankfully accept [one-time and recurring](https://opencollective.com/typelevel/donate) contributions as well.

Getting Started

Cats is available for Scala.js and Scala Native, as well as the standard JVM runtime.

Cats relies on improved type inference via the fix for SI-2712, which is not enabled by default. For Scala 2.12 you should add the following to your build.sbt:

scala
scalacOptions += "-Ypartial-unification"

(Partial unification is on by default since Scala 2.13, the compiler no longer accepts -Ypartial-unification)

And then create the Cats dependency, by adding the following to your build.sbt:

scala
libraryDependencies += "org.typelevel" %% "cats-core" % "2.9.0"

This will pull in the cats-core module. If you require some other
functionality, you can pick-and-choose from amongst these modules
(used in place of "cats-core"):

  • cats-kernel: Small set of basic type classes (required).
  • cats-core: Most core type classes and functionality (required).
  • cats-laws: Laws for testing type class instances.
  • cats-free: Free structures such as the free monad, and supporting type classes.
  • cats-testkit: lib for writing tests for type class instances using laws.
  • algebra: Type classes to represent algebraic structures.
  • alleycats-core: Cats instances and classes which are not lawful.

There are several other Cats modules that are in separate repos so that they can
maintain independent release cycles.

  • cats-effect: standard IO type together with Sync, Async and Effect type classes
  • cats-mtl: transformer typeclasses for Cats' Monads, Applicatives and Functors.
  • mouse: a small companion to Cats that provides convenient syntax (aka extension methods)
  • kittens: automatic type class instance derivation for Cats and generic utility functions
  • cats-tagless: Utilities for tagless final encoded algebras
  • cats-collections: Data structures which facilitate pure functional programming
  • cats-testkit-scalatest: Cats testkit integration with Scalatest

Past release notes for Cats are available in CHANGES.md.

Documentation

Links:

  1. Website: typelevel.org/cats/
  2. ScalaDoc: typelevel.org/cats/api/
  3. Type classes: typelevel.org/cats/typeclasses.html
  4. Data types: typelevel.org/cats/datatypes.html
  5. Algebra overview: typelevel.org/cats/algebra.html
  6. Glossary: typelevel.org/cats/nomenclature.html
  7. Resources for Learners: typelevel.org/cats/resources_for_learners.html
  8. FAQ: typelevel.org/cats/faq.html
  9. The Typelevel Ecosystem: typelevel.org/cats/typelevelEcosystem.html

Community

Discussion around Cats is currently happening on GitHub issues, PR pages,
and Discord:

The Typelevel Discord has #cats and #cats-dev
channels, as well as community channels such as #beginners. Please join us!

People are expected to follow the
Typelevel Code of Conduct when
discussing Cats on GitHub, Discord, or other venues.

We hope that our community will be respectful, helpful, and kind. If
you find yourself embroiled in a situation that becomes heated, or
that fails to live up to our expectations, you should disengage and
contact one of the project maintainers in private. We
hope to avoid letting minor aggressions and misunderstandings escalate
into larger problems.

If you are being harassed, please contact one of us
immediately so that we can support you.

Binary compatibility and versioning

After 1.0.0 release, we decided
to use MAJOR.MINOR.PATCH Semantic Versioning 2.0.0
going forward, which is different from the EPOCH.MAJOR.MINOR scheme common among
Java and Scala libraries (including the Scala lang).

Cats strives to provide a solid and stable foundation for an ecosystem of
FP libraries. Thus, we treat backward binary compatibility maintenance with a high priority.
In semantic versioning, backward breaking change is ONLY allowed between MAJOR versions.
We will maintain backward binary compatibility between PATCH AND MINOR versions.
For example, when we release Cats 1.1.0, it will be backward binary compatible
with the previous 1.0.x versions. I.E. the new JAR will be a drop-in replacement for
the old one. This is critical when your application has a diamond
dependency on Cats - depending on two or more libraries that all depend on Cats.
If one library upgrades to the new 1.1.0 Cats before the other one does, your
application still runs thanks to this backward binary compatibility.

Also worth noting is that according to semantic versioning,
MINOR version Y (x.Y.z | x > 0) MUST be incremented
if new, backwards compatible functionality is introduced to the public API.
It MUST be incremented if any public API functionality is marked as deprecated.

Any binary breaking changes will require a MAJOR version bump, which we will be very
cautious about. We will also consider using organization and package name for major
versioning in the future. But that decision is yet to be made.

Adopters

A (non-exhaustive) list of companies that use Cats in production is featured in ADOPTERS.md. Don't see yours? You can add it in a PR! And if you can, consider supporting us.

Maintainers

The current maintainers (people who can merge pull requests) are:

Retired committers include:

We are currently following a practice of requiring at least two
sign-offs to merge code PRs (and for large or contentious issues we may
wait for more). For typos, documentation improvements or minor build fix we
relax this to a single sign-off. More detail in the process document.

All code is available to you under the MIT license, available at
http://opensource.org/licenses/mit-license.php and also in the
COPYING file. The design is informed by many other
projects, in particular Scalaz.

Copyright the maintainers, 2015-2025.


Overview (`scalafix/README.md`)

Scalafix rules for cats

How to use

  1. Install the Scalafix sbt plugin

  2. Run the rules appropriate to your Cats version (see below)

Migration to Cats v2.2.0

First configure the SemanticDB compiler plugin to enable synthetics:

text
ThisBuild / scalacOptions += "-P:semanticdb:synthetics:on"

Then run Scalafix:

sh
sbt scalafixAll github:typelevel/cats/Cats_v2_2_0

Available rules

  • Type class instances are now available in implicit scope, so there is a rule to
    remove imports that are no longer needed

Migration to Cats v1.0.0

sh
sbt scalafixAll github:typelevel/cats/Cats_v1_0_0

Available rules

  • All Unapply enabled methods, e.g. sequenceU, traverseU, etc. are removed. Unapply enabled syntax ops are also removed. Please use the partial unification SI-2712 fix instead. The easiest way might be this sbt-plugin.

  • The creation methods (left, right, apply, pure, etc.) in EitherT were improved to take less type arguments.

  • EitherT.liftT was renamed to EitherT.liftF

  • the lift method on WriterT, StateT, RWST and Kleisli was renamed to liftF

  • CartesianBuilder (i.e. |@|) syntax is deprecated, use the apply syntax on tuples instead. E.g. (x |@| y |@| z).map(...) should be replaced by (x, y, z).mapN(...)

  • Free.suspend is renamed to Free.defer for consistency.

  • traverse1_, intercalate1 and sequence1_ in Reducible were renamed to nonEmptyTraverse_, nonEmptyIntercalate and nonEmptySequence_ respectively.

  • cats.free.Inject is moved from cats-free to cats-core and renamed to cats.InjectK; cats.data.Prod is renamed to cats.data.Tuple2K; cats.data.Coproduct is renamed to cats.data.EitherK

  • Apply syntax on tuple (e.g. (x, y, z).map3(...)) was moved from cats.syntax.tuple._ to cats.syntax.apply._ and renamed to mapN, contramapN and imapN respectively.

  • Apply methods forEffect and followedBy were renamed to productL and productR respectively. This also effects forEffectEval, followedByEval, forEffectPar, and followedByPar.

  • Split is removed, and the method split is moved to Arrow. Note that only under CommutativeArrow does it guarantee the non-interference between the effects. see #1567

WIP

  • cats no longer publishes the all-inclusive bundle package "org.typelevel" % "cats", use cats-core, cats-free, or cats-law accordingly instead. If you need cats.free, use "org.typelevel" % "cats-free", if you need cats-laws use "org.typelevel" % "cats-laws", if neither, use "org.typelevel" % "cats-core".

  • FunctorFilter, MonadCombine, MonadFilter, MonadReader, MonadState, MonadTrans, MonadWriter and TraverseFilter are no longer in cats, the functionalities they provided are inhereted by the new cats-mtl project. Please check here for migration guide.

  • Several cats-core type class instances for cats.kernel were moved from their companion objects to separate traits and thus require imports from cats.instances.xxx._ (or the recommended import cats.implicits._) now. See #1659 for more details.

  • foldLeftM is removed from Free, use foldM on Foldable instead, see #1117 for detail.

  • iteratorFoldM was removed from Foldable due to #1716

To test the Scalafix rules

bash
cd scalafix
sbt test

Index (`docs/index.md`)

Cats



Overview

Cats is a library which provides abstractions for functional programming in the Scala programming language.

Scala supports both object-oriented and functional programming, and this is reflected in the hybrid approach of the
standard library. Cats strives to provide functional programming abstractions that are core, binary compatible, modular, approachable and efficient. A broader goal of Cats is to provide a foundation for an ecosystem of pure, typeful libraries to support functional programming in Scala applications.

For more detail about Cats' motivations, go here.

Why "cats"?

The name is a playful shortening of the word category, from "category theory".

Regardless, you do not need to know anything about category theory to use Cats.

Contributors

Code Contributors

This project exists thanks to all the people who contribute. We welcome contributions to Cats and would love for you to help build
Cats. See our contributor guide for more
information about how you can get involved as a developer. If you are looking for something to start with, here is a beginner friendly list.

Financial Contributors

Become a financial contributor and help us sustain our community. Donations directly support office hours for maintainers, better documentation and strategic initiatives.

Platinum Sponsors

[Platinum sponsorship](https://opencollective.com/typelevel/contribute/platinum-sposor-12420/checkout) starts at $950 USD/month.

Gold Sponsors

[Gold Sponsorship](https://opencollective.com/typelevel/contribute/gold-sponsor-12419/checkout) starts at $420 USD/month.

Silver Sponsors

[Silver Sponsorship](https://opencollective.com/typelevel/contribute/silver-sponsor-11780/checkout) starts at $180 USD/month.

Backers

Become a [Backer](https://opencollective.com/typelevel/contribute/backer-11779/checkout) with a recurring donation of just $5 USD/month.

Other contributors

We thankfully accept [one-time and recurring](https://opencollective.com/typelevel/donate) contributions as well.

Getting Started

Cats is available for Scala.js and Scala Native, as well as the standard JVM runtime.

Cats relies on improved type inference via the fix for SI-2712, which is not enabled by default. For Scala 2.12 you should add the following to your build.sbt:

scala
scalacOptions += "-Ypartial-unification"

(Partial unification is on by default since Scala 2.13, the compiler no longer accepts -Ypartial-unification)

And then create the Cats dependency, by adding the following to your build.sbt:

scala
libraryDependencies += "org.typelevel" %% "cats-core" % "@VERSION@"

This will pull in the cats-core module. If you require some other
functionality, you can pick-and-choose from amongst these modules
(used in place of "cats-core"):

  • cats-kernel: Small set of basic type classes (required).
  • cats-core: Most core type classes and functionality (required).
  • cats-laws: Laws for testing type class instances.
  • cats-free: Free structures such as the free monad, and supporting type classes.
  • cats-testkit: lib for writing tests for type class instances using laws.
  • algebra: Type classes to represent algebraic structures.
  • alleycats-core: Cats instances and classes which are not lawful.

There are several other Cats modules that are in separate repos so that they can
maintain independent release cycles.

  • cats-effect: standard IO type together with Sync, Async and Effect type classes
  • cats-mtl: transformer typeclasses for Cats' Monads, Applicatives and Functors.
  • mouse: a small companion to Cats that provides convenient syntax (aka extension methods)
  • kittens: automatic type class instance derivation for Cats and generic utility functions
  • cats-tagless: Utilities for tagless final encoded algebras
  • cats-collections: Data structures which facilitate pure functional programming
  • cats-testkit-scalatest: Cats testkit integration with Scalatest

Past release notes for Cats are available in CHANGES.md.

Community

Discussion around Cats is currently happening on GitHub issues, PR pages,
and Discord:

The Typelevel Discord has #cats and #cats-dev
channels, as well as community channels such as #beginners. Please join us!

People are expected to follow the
Typelevel Code of Conduct when
discussing Cats on GitHub, Discord, or other venues.

We hope that our community will be respectful, helpful, and kind. If
you find yourself embroiled in a situation that becomes heated, or
that fails to live up to our expectations, you should disengage and
contact one of the project maintainers in private. We
hope to avoid letting minor aggressions and misunderstandings escalate
into larger problems.

If you are being harassed, please contact one of us
immediately so that we can support you.

Binary compatibility and versioning

After 1.0.0 release, we decided
to use MAJOR.MINOR.PATCH Semantic Versioning 2.0.0
going forward, which is different from the EPOCH.MAJOR.MINOR scheme common among
Java and Scala libraries (including the Scala lang).

Cats strives to provide a solid and stable foundation for an ecosystem of
FP libraries. Thus, we treat backward binary compatibility maintenance with a high priority.
In semantic versioning, backward breaking change is ONLY allowed between MAJOR versions.
We will maintain backward binary compatibility between PATCH AND MINOR versions.
For example, when we release Cats 1.1.0, it will be backward binary compatible
with the previous 1.0.x versions. I.E. the new JAR will be a drop-in replacement for
the old one. This is critical when your application has a diamond
dependency on Cats - depending on two or more libraries that all depend on Cats.
If one library upgrades to the new 1.1.0 Cats before the other one does, your
application still runs thanks to this backward binary compatibility.

Also worth noting is that according to semantic versioning,
MINOR version Y (x.Y.z | x > 0) MUST be incremented
if new, backwards compatible functionality is introduced to the public API.
It MUST be incremented if any public API functionality is marked as deprecated.

Any binary breaking changes will require a MAJOR version bump, which we will be very
cautious about. We will also consider using organization and package name for major
versioning in the future. But that decision is yet to be made.

Adopters

A (non-exhaustive) list of companies that use Cats in production is featured on the Adopters page. Don't see yours? You can add it in a PR! And if you can, consider supporting us.

Maintainers

The current maintainers (people who can merge pull requests) are:

Retired committers include:

We are currently following a practice of requiring at least two
sign-offs to merge code PRs (and for large or contentious issues we may
wait for more). For typos, documentation improvements or minor build fix we
relax this to a single sign-off. More detail in the process document.

All code is available to you under the MIT license, available at
http://opensource.org/licenses/mit-license.php and also in the
COPYING file. The design is informed by many other
projects, in particular Scalaz.

Copyright the maintainers, 2015-2024.


Algebra (`docs/algebra.md`)

{% laika.title = Algebra %}

Algebra Overview

Algebra uses type classes to represent algebraic structures. You can use these type classes to represent the abstract capabilities (and requirements) you want generic parameters to possess.

This section will explain the structures available.

algebraic properties and terminology

We will be talking about properties like associativity and commutativity. Here is a quick explanation of what those properties mean:

Name Description
Associative If ⊕ is associative, then a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c.
Commutative If ⊕ is commutative, then a ⊕ b = b ⊕ a.
Identity If id is an identity for ⊕, then a ⊕ id = id ⊕ a = a.
Inverse If ¬ is an inverse for ⊕ and id, then a ⊕ ¬a = ¬a ⊕ a = id.
Distributive If ⊕ and ⊙ distribute, then a ⊙ (b ⊕ c) = (a ⊙ b) ⊕ (a ⊙ c) and (a ⊕ b) ⊙ c = (a ⊙ c) ⊕ (b ⊙ c).
Idempotent If ⊕ is idempotent, then a ⊕ a = a. If f is idempotent, then f(f(a)) = f(a)

Though these properties are illustrated with symbolic operators, they work equally-well with functions. When you see a ⊕ b that is equivalent to f(a, b): ⊕ is an infix representation of the binary function f, and a and b are values (of some type A).

Similarly, when you see ¬a that is equivalent to g(a): ¬ is a prefix representation of the unary function g, and a is a value (of some type A).

basic algebraic structures

The most basic structures can be found in the algebra package. They all implement a method called combine, which is associative. The identity element (if present) will be called empty, and the inverse method (if present) will be called inverse.

Name Associative? Commutative? Identity? Inverse? Idempotent?
Semigroup ✓
CommutativeSemigroup ✓ ✓
Monoid ✓ ✓
Band ✓ ✓
Semilattice ✓ ✓ ✓
Group ✓ ✓ ✓
CommutativeMonoid ✓ ✓ ✓
CommutativeGroup ✓ ✓ ✓ ✓
BoundedSemilattice ✓ ✓ ✓ ✓

(For a description of what each column means, see §algebraic properties and terminology.)

ring-like structures

The algebra.ring package contains more sophisticated structures which combine an additive operation (called plus) and a multiplicative operation (called times). Additive identity and inverses will be called zero and negate (respectively); multiplicative identity and inverses will be called one and reciprocal (respectively).

All ring-like structures are associative for both + and *, have commutative +, and have a zero element (an identity for +).

Name Has negate? Has 1? Has reciprocal? Commutative *?
Semiring
Rng ✓
Rig ✓
CommutativeRig ✓ ✓
Ring ✓ ✓
CommutativeRing ✓ ✓ ✓
Semifield ✓ ✓
CommutativeSemifield ✓ ✓ ✓
Field ✓ ✓ ✓ ✓

(For a description of what the terminology in each column means, see §algebraic properties and terminology.)

lattice-like structures

The algebra.lattice package contains more structures that can be somewhat ring-like. Rather than plus and times we have meet and join both of which are always associative, commutative and idempotent, and as such each can be viewed as a semilattice. Meet can be thought of as the greatest lower bound of two items while join can be thought of as the least upper bound between two items.

When zero is present, join(a, zero) = a. When one is present meet(a, one) = a.

When meet and join are both present, they obey the absorption law:

  • meet(a, join(a, b)) = join(a, meet(a, b)) = a

Sometimes meet and join distribute, we say it is distributive in this case:

  • meet(a, join(b, c)) = join(meet(a, b), meet(a, c))
  • join(a, meet(b, c)) = meet(join(a, b), join(a, c))

Sometimes an additional binary operation imp (for impliciation, also written as →, meet written as ∧) is present. Implication obeys the following laws:

  • a → a = 1
  • a ∧ (a → b) = a ∧ b
  • b ∧ (a → b) = b
  • a → (b ∧ c) = (a → b) ∧ (a → c)

The law of the excluded middle can be expressed as:

  • (a ∨ (a → 0)) = 1
Name Has join? Has meet? Has zero? Has one? Distributive Has imp? Excludes middle?
JoinSemilattice ✓
MeetSemilattice ✓
BoundedJoinSemilattice ✓ ✓
BoundedMeetSemilattice ✓ ✓
Lattice ✓ ✓
DistributiveLattice ✓ ✓ ✓
BoundedLattice ✓ ✓ ✓ ✓
BoundedDistributiveLattice ✓ ✓ ✓ ✓ ✓
Heyting ✓ ✓ ✓ ✓ ✓ ✓
Bool ✓ ✓ ✓ ✓ ✓ ✓ ✓

Note that a BoundedDistributiveLattice gives you a CommutativeRig, but not the other way around: rigs aren't distributive with a + (b * c) = (a + b) * (a + c).

Also, a Bool gives rise to a BoolRing, since each element can be defined as its own negation. Note, Bool's .asBoolRing is not an extension of the .asCommutativeRig method as the plus operations are defined differently.

Documentation Help

We'd love your help with this documentation! You can edit this page in your browser by clicking this link.


Alleycats (`docs/alleycats.md`)

Alleycats

Overview

Alleycats is a module of the Cats
project that exists to support types which are not entirely savory or
law-abiding but which may prove useful or necessary in some
situations.

In some cases, a type class instance can almost (but not quite) obey
the required laws (e.g. a Monad instance for scala.util.Try). In
other cases, type classes which lack laws or constraints may still be
useful in some cases (e.g. Empty[_], a type class which provides
some notion of "emptiness").

Rather than argue about whether to permit these types in Cats proper, we
provide a (slightly disreputable) home for them here.

Type classes

Alleycats introduces several new type classes. Here is an overview of
the instances introduced.

Empty\[A\], Zero\[A\], and One\[A\]

A commonly-requested type class is one that encodes the idea of a set
having an identity element. Normally this would be done by defining a
Monoid[A] instance, but in some cases the idea of emptiness is
independent of a particular associative operation.

In this case, Empty[A] may be used in place of Monoid[A]. It
provides access to the identity element (via the .empty method),
and can also provide .isEmpty and .nonEmpty if an Eq[A] is
available.

The two other type classes, Zero[A] and One[A], are similar,
except they correspond to AdditiveMonoid[A] and
MultiplicativeMonoid[A] (found in the algebra.ring package). Their
methods are called zero and one, respectively.

While none of these type classes have their own laws, they are
required not to violate the monoid laws when applicable. This means
that if Empty[A] and Semigroup[A] are both available, that
Empty[A].empty must function as an identity element for
Semigroup[A].combine. In fact, together these instances can be
viewed as a Monoid[A] (and there is an implicit method to that
effect).

The same rules apply to Zero[A] and One[A] and their respective
associative operations.

Pure\[F\[\_\]\] and Extract\[F\[\_\]\]

The Pure[F] type class represents the pure method of
Applicative[F] separated from its map and ap methods. Like the
previous type classes, if Pure[F] and Apply[F] are both available
they are required to be consistent (and should provide a valid
Applicative[F] instance).

Similarly, Extract[F] represents the extract method of
Comonad[F] without coflatMap and map methods. When Extract[F]
and CoflatMap[F] are available, they should provide a valid
Comonad[F] instance.

EmptyK\[F\[\_\]\]

Finally, EmptyK[F] generalizes the empty[A] method from
MonoidK[F]. The pattern here is the same as before --
SemigroupK[F] and EmptyK[F] should provide a valid MonoidK[F]
instance.

Instances

Alleycats also provides some "disreputable" type class instances.

Set\[\_\] instances

Scala's Set[_] takes advantage of the universal availability of
.hashCode and .equals. This makes it difficult to use
parametricity
to reason about sets, and casts some doubt on their use with functors
and monads.

Alleycats provides Monad[Set] and Traverse[Set]. You can import
these instances via import alleycats.std.set._.

Try\[\_\] instances

Scala's Try[_] is intended to replace the need for try { ... } catch { ... } syntax in Scala programs, to ease error-handling, and
to transport exceptions as data. Due to the way Try transparently
catches exceptions in .map and .flatMap, some people are skeptical
that Try fulfills the necessary functor/monad laws.

Alleycats provides a Monad[Try]. You can import this instance via
import alleycats.std.try_._.

Iterable\[\_\] instances

Scala's collection.Iterable[_] offers no guarantees that it's immutable,
since it abstracts over the mutable and immutable variants. However it's
the type used to represent a Maps values, and its often desirable to treat the
values of a map as a Foldable collection. Alleycats provides a Foldable[Iterable], eg:

text
import cats.syntax.all._
import alleycats.std.iterable._

// Result "AppleOrange"
Map(1 -> "Apple", 2 -> "Orange").values.combineAll

Contributing

This module's goal is to be very liberal about accepting type class
instances, but to only provide instances which are absent from
Cats proper. Law-abiding instances will end up in Cats, and everything else will
end up here.


Colophon (`docs/colophon.md`)

Colophon

Cats has been made a much better project, and is a much more enjoyable
project to work on because of many of the other projects on which Cats
is built. Many of these projects have had enhancements made in order
to benefit Cats, for which we are grateful.

We would like to thank the maintainers of these supporting projects,
and we'd encourage you to check out these projects and consider
integrating them into your own projects.

  • scalacheck for property-based testing
  • discipline for encoding and testing laws
  • kind-projector for type lambda syntax
  • mdoc type-checked example code makes sure that our examples stay in sync with the rest of our source

There are other libraries that aim to foster Functional Programming in the Scala programming language which Cats has a relationship to:

  • scalaz The project which directly inspires Cats. Currently Cats borrows some code directly from scalaz.
  • Structures A project very similar in
    nature to Cats, also derived from scalaz. The Structures and Cats
    projects have had a healthy relationship of sharing both ideas and code.

For a full list of Cats and Typelevel related projects and libraries, take a look at The Typelevel Ecosystem


Datatypes (`docs/datatypes.md`)

{% laika.title = "Data Types" %}

@:navigationTree {
entries = [ { target = "datatypes", depth = 2 } ]
}


Faq (`docs/faq.md`)

{% laika.title = FAQ %}

Frequently Asked Questions

@:navigationTree {
entries = [ { target = "faq.md", depth = 2 } ]
}

What imports do I need?

The easiest approach to Cats imports is to import everything that's commonly needed:

scala mdoc:silent
import cats._
import cats.data._
import cats.syntax.all._

This should be all that you need, but if you'd like to learn more about the details of imports than you can check out the import guide.

I am new to pure functional programming, what quick wins can I get from Cats?

Please refer to the jump start guide.

What is the difference between Cats and Scalaz?

Cats and Scalaz have the same goal: to facilitate pure functional programming in Scala applications. However the underlying core strategy is different; Scalaz took the approach of trying to provide a single batteries-included standard library for FP that powers the Scala applications. Cats, on the other hand, aims to help build an ecosystem of pure FP libraries by providing a solid and stable foundation; these libraries can have their own styles and personalities, competing with each other, while at the same time playing nice. It is through this ecosystem of FP libraries (cats included) that Scala applications can be powered with "FP awesome-ness" and beyond by picking whatever best fit their needs.

Based on this core strategy, Cats takes a modular approach and focuses on providing core, binary compatible, approachable and efficient abstractions. It provides a welcoming and supportive environment for the user community governed by the Typelevel Code of Conduct. It also takes great effort in supplying a comprehensive and beginner-friendly documentation.

Where is right-biased Either?

Up through Cats 0.7.x we had cats.data.Xor, which was effectively scala.util.Either, but right-biased by default and with
a bunch of useful combinators around it. In Scala 2.12.x Either
became right-biased so we revisited the use of Xor and
decided that in the interest of interoperability, we would remove Xor in the Cats 0.8.0 release and
fill in the gaps in the scala.util.Either API via
syntax enrichment.

This syntax and the type class instances for Either can be imported using cats.syntax._, which will also bring in syntactic enrichment and instances for other standard library types, or you can import only the Either enrichment with cats.syntax.either._.

There are a few minor mismatches between Xor and Either. For example, in some cases you may need to specify a type parameter for an enrichment method on Either (such as leftMap) even though it was properly inferred for Xor, due to Either having covariant type parameters.

Similarly, cats.data.XorT has been replaced with cats.data.EitherT, although since this is a type defined in Cats, you don't need to import syntax or instances for it (although you may need imports for the underlying monad).

Why is the compiler having trouble with types with more than one type parameter?

When you encounter a situation where the same code works fine with a type with one type parameter, e.g. List[A], but doesn't work with types with more than one, e.g. Either[A, B], you probably hit SI-2712. Without going into the details, it's highly recommended to enable a partial SI-2712 fix in your project. The easiest way to achieve that is through this sbt plugin.
Cats used to provide mitigation to this issue semi-transparently, but given the fact that the fix is now mainstream, we decided to drop that mitigation machinery in favor of reducing the complexity. See this issue for details.

Why is some example code not compiling for me?

A portion of example code requires either the Kind-projector compiler plugin or partial unification turned on in scalac. The easiest way to turn partial unification on is through this sbt plugin.

Why can't the compiler find implicit instances for Future?

If you have already followed the imports advice but are still getting error messages like could not find implicit value for parameter e: cats.Monad[scala.concurrent.Future] or value |+| is not a member of scala.concurrent.Future[Int], then make sure that you have an implicit scala.concurrent.ExecutionContext in scope. The easiest way to do this is to import scala.concurrent.ExecutionContext.Implicits.global, but note that you may want to use a different execution context for your production application.

Where are implicit instances for `Seq`?

As of cats-2.3, instances for collection.immutable.Seq are provided by cats.
Mind that, up to scala-2.12, Seq was an alias for collection.Seq and lawful instances can't be provided for it due to its potential mutability.
In scala-2.13, Seq was changed to collection.immutable.Seq which greatly improves Seq's interoperability with cats.

How can I turn my List of `` into a `` of a list?

It's really common to have a List of values with types like Option, Either, or Validated that you would like to turn "inside out" into an Option (or Either or Validated) of a List. The sequence and traverse methods are really handy for this. You can read more about them in the Traverse documentation.

Where is ListT?

There are monad transformers for various types, such as OptionT, so people often wonder why there isn't a ListT. For example, in the following example, people might reach for ListT to simplify making nested map and exists calls:

scala mdoc:reset:silent
val l: Option[List[Int]] = Some(List(1, 2, 3, 4, 5))

def isEven(i: Int): Boolean = i % 2 == 0
scala mdoc
l.map(_.map(_ + 1))
l.exists(_.exists(isEven))

A naive implementation of ListT suffers from associativity issues; see this gist for an example. It's possible to create a ListT that doesn't have these issues, but it tends to be pretty inefficient. For many use-cases, Nested can be used to achieve the desired results.

Here is how we could achieve the effect of the previous example using Nested:

scala mdoc:silent
import cats.data.Nested
import cats.syntax.all._
scala mdoc
val nl = Nested(l)
nl.map(_ + 1)
nl.exists(isEven)

We can even perform more complicated operations, such as a traverse of the nested structure:

scala mdoc:silent
import cats.data.ValidatedNel
type ErrorsOr[A] = ValidatedNel[String, A]
def even(i: Int): ErrorsOr[Int] = if (i % 2 == 0) i.validNel else s"$i is odd".invalidNel
scala mdoc
nl.traverse(even)

Where are `Applicative`s for monad transformers?

An Applicative instance for OptionT[F, *]/EitherT[F, E, *], built without a corresponding Monad instance for F, would be unlawful, so it's not included. See the guidelines for a more detailed explanation.

As an alternative, using .toNested on the monad transformer is recommended, although its ap will still be inconsistent with the Monad instance's.`.

Where is IO/Task?

In purely functional programming, a monadic IO or Task type is often used to handle side effects such as file/network IO. In some languages and frameworks, such a type also serves as the primary abstraction through which parallelism is achieved. Nearly every real-world purely functional application or service is going to require such a data type, and this gives rise to an obvious question: why doesn't Cats include such a type?

The answer is that Cats does include an IO, it just isn't included in the core library. The decision was made to split IO away from cats-core and (indeed the whole Cats release cycle!) in order to make it easier to ensure modular versioning and compatibility across the ecosystem. The cats-effect project defines a type, cats.effect.IO, which is intended to be a very minimal, very performant data type for managing synchronous and asynchronous side-effects, integrated into the Cats ecosystem.

However, we acknowledge that this type may not meet everyone's needs. The cats-effect project characterizes the space of side-effect-capturing data types with a set of typeclasses (deriving from cats.Monad), and so all such data types are, broadly-speaking, mutually compatible and interchangeable in many generic contexts. For example, Monix provides support for IO, concurrency, and streaming and integrates with the cats-effect type classes.

It may be worth keeping in mind that IO and Task are pretty blunt instruments (they are essentially the Any of side effect management), and you may want to narrow the scope of your effects throughout most of your application. The free monad documentation describes a way to abstractly define controlled effects and interpret them into a type such as IO or Task as late as possible. As more of your code becomes pure through these controlled effects the less it matters which type you end up choosing to represent your side effects.

What do types like `?` and `λ` mean?

Cats defines a wealth of type classes and type class instances. For a number of the type class and instance combinations, there is a mismatch between the type parameter requirements of the type class and the type parameter requirements of the data type for which the instance is being defined. For example, the Either data type is a type constructor with two type parameters. We would like to be able to define a Monad for Either, but the Monad type class operates on type constructors having only one type parameter.

Enter type lambdas! Type lambdas provide a mechanism to allow one or more of the type parameters for a particular type constructor to be fixed. In the case of Either then, when defining a Monad for Either, we want to fix one of the type parameters at the point where a Monad instance is summoned, so that the type parameters line up. As Either is right biased, a type lambda can be used to fix the left type parameter and allow the right type parameter to continue to vary when Either is treated as a Monad.

Enter kind-projector! kind-projector is a compiler plugin which provides a convenient syntax for dealing with type lambdas. The symbols ? and λ are treated specially by kind-projector, and expanded into the more verbose definitions that would be required were it not to be used. You can read more about kind-projector at the project page.

What is `tailRecM`?

The FlatMap type class has a tailRecM method with the following signature:

scala
def tailRecM[A, B](a: A)(f: A => F[Either[A, B]]): F[B]

When you are defining a FlatMap instance, its tailRecM implementation must have two properties in order for the instance to be considered lawful. The first property is that tailRecM must return the same result that you would get if you recursively called flatMap until you got a Right value (assuming you had unlimited stack space—we'll get to that in a moment). In other words, it must give the same result as this implementation:

scala mdoc:silent
trait Monad[F[_]] {
  def pure[A](x: A): F[A] = ???
  def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B] = ???

  def tailRecM[A, B](a: A)(f: A => F[Either[A, B]]): F[B] =
    flatMap(f(a)) {
      case Right(b) => pure(b)
      case Left(nextA) => tailRecM(nextA)(f)
    }
}

The reason we can't simply use this implementation for all type constructors (and the reason that tailRecM is useful at all) is that for many monadic types, recursively flatMap-ing in this way will quickly exhaust the stack.

Option is one example of a monadic type whose flatMap consumes stack in such a way that nesting flatMap calls deeply enough (usually around a couple thousand levels) will result in a stack overflow. We can provide a stack-safe tailRecM implementation for Option, though:

scala mdoc:silent
import cats.FlatMap
import scala.annotation.tailrec

implicit val optionFlatMap: FlatMap[Option] = new FlatMap[Option] {
  def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa.map(f)
  def flatMap[A, B](fa: Option[A])(f: A => Option[B]): Option[B] = fa.flatMap(f)

  @tailrec
  def tailRecM[A, B](a: A)(f: A => Option[Either[A, B]]): Option[B] = f(a) match {
    case None => None
    case Some(Left(a1)) => tailRecM(a1)(f)
    case Some(Right(b)) => Some(b)
  }
}

Now we don't have to worry about overflowing the stack, no matter how many times we have to call tailRecM before we get a Right.

This is useful because any operation that you would write using recursive flatMaps can be rewritten to use tailRecM, and if the FlatMap instance for your type constructor is lawful, you don't have to worry about stack safety.

The downside is that how you write a lawful tailRecM for your type constructor may not always be obvious. For some type constructors, such as Future, recursively flatMap-ing is already safe, and the first simple implementation above will be lawful. For types like Option and Try, you'll need to arrange the recursion in such a way that the tailRecM calls are tail calls (which you can confirm with Scala's tailrec annotation). Collection types require yet another approach (see for example the implementation for List).

If you're having trouble figuring out how to implement tailRecM lawfully, you can try to find an instance in Cats itself for a type that is semantically similar to yours (all of the FlatMap instances provided by Cats have lawful, stack-safe tailRecM implementations).

In some cases you may decide that providing a lawful tailRecM may be impractical or even impossible (if so we'd like to hear about it). For these cases we provide a way of testing all of the monad laws except for the stack safety of tailRecM: just replace MonadTests[F].monad[A, B, C] in your tests with MonadTests[F].stackUnsafeMonad[A, B, C].

What does this symbol mean?

Below is a list of symbols used in Cats.

The ~>, ⊥, ⊤, :<: and :≺: symbols can be imported with import cats._.

All other symbols can be imported with import cats.syntax.all._

Symbol Name Nickname Type Class Signature
fa *> fb product right Apply[F[_]] productR(fa: F[A])(fb: F[B]): F[B]
fa <* fb product left Apply[F[_]] productL(fa: F[A])(fb: F[B]): F[A]
x === y equals Eq[A] eqv(x: A, y: A): Boolean
x =!= y not equals Eq[A] neqv(x: A, y: A): Boolean
fa >>= f flatMap FlatMap[F[_]] flatMap(fa: F[A])(f: A => F[B]): F[B]
fa >> fb followed by FlatMap[F[_]] >>(fb: => F[B]): F[B]
x &#124;-&#124; y remove Group[A] remove(x: A, y: A): A
x > y greater than PartialOrder[A] gt(x: A, y: A): Boolean
x >= y greater than or equal PartialOrder[A] gteq(x: A, y: A): Boolean
x < y less than PartialOrder[A] lt(x: A, y: A): Boolean
x <= y less than or equal PartialOrder[A] lteq(x: A, y: A): Boolean
x &#124;+&#124; y Semigroup combine Semigroup[A] combine(x: A, y: A): A
x <+> y SemigroupK combine SemigroupK[F[_]] combineK(x: F[A], y: F[A]): F[A]
f <<< g Arrow compose Compose[F[_, _]] compose(f: F[B, C], g: F[A, B]): F[A, C]
f >>> g Arrow andThen Compose[F[_, _]] andThen(f: F[A, B], g: F[B, C]): F[A, C]
f &&& g Arrow merge Arrow[F[_, _]] merge[A, B, C](f: F[A, B], g: F[A, C]): F[A, (B, C)]
f -< g Arrow combine and bypass Arrow[F[_, _]] combineAndByPass[A, B, C](f: F[A, B], g: F[B, C]): F[A, (B, C)]
F ~> G natural transformation FunctionK[F[_], G[_]] FunctionK alias
F :<: G injectK InjectK[F[_], G[_]] InjectK alias
F :≺: G injectK InjectK[F[_], G[_]] InjectK alias
fa &> fb parallel product right Parallel[M[_]] parProductR[A, B](ma: M[A])(mb: M[B]): M[B]
fa <& fb parallel product left Parallel[M[_]] parProductL[A, B](ma: M[A])(mb: M[B]): M[A]
⊥ bottom N/A Nothing
⊤ top N/A Any
fa << fb (Deprecated) product left FlatMap[F[_]] productL(fa: F[A])(fb: F[B]): F[A]

How can I test instances against their type classes' laws?

You can find more information here.

How can I help?

The Сats community welcomes and encourages contributions, even if you are completely new to Сats and functional programming. Here are a few ways to help out:

  • Find an undocumented method and write a ScalaDoc entry for it. See Arrow.scala for some examples of ScalaDoc entries that use sbt-doctest.
  • Find an open issue, leave a comment on it to let people know you are working on it, and submit a pull request. If you are new to Сats, you may want to look for items with the low-hanging-fruit label.

See the contributing guide for more information.

How to try Cats in a REPL?

The easiest way is probably using Ammonite-REPL. Install it following the instructions there. Then in the amm console you can type in

scala
// interp.configureCompiler(_.settings.YpartialUnification.value = true) // If using scala 2.11 or 2.12
import $ivy.`org.typelevel::cats-core:2.1.1`, cats._, cats.data._, cats.implicits._

Or if you want, you can add these lines to ~/.ammonite/predef.sc so that they are enabled every ammonite session.

Why aren't monad transformers like `OptionT` and `EitherT` covariant like `Option` and `Either`?

Please see Variance of Monad Transformers on the Typelevel blog.

Why isn't `Set` a lawful `Functor` (and hence `Applicative`, `Monad`, etc.)?

Although in many cases Set can behave as a Functor indeed, there are some edge cases where it doesn't.
For example, Set can violate the "covariant composition" law of Functor, which is:

text
fa.map(f).map(g) <-> fa.map(f.andThen(g))

Since Set is internally based on universal hashing and equality, it violates this law when used with a data type that
overrides equals and hashCode in a such a way that its instances may appear equal but de-facto contain different
values. One example of this type is scala.concurrent.duration.Duration:

scala mdoc
import scala.concurrent.duration.*

val f: String => Duration = Duration.apply
val g: Duration => String = _.toString

val set = Set("1 minute", "60 seconds", "60000 milliseconds")

set.map(f).map(g) // ==> Set("1 minute")
set.map(f.andThen(g)) // ==> Set("1 minute", "60 seconds", "60000 milliseconds")

Another good real-world example to be aware of is CIString.

That said, there's a Monad[Set] instance in the Alleycats
module, which you can use on your own risk if you are sure about data types you are working with.


Guidelines (`docs/guidelines.md`)

Guidelines

All guidelines in Сats should have clear justifications. There is no room for tribal wisdom in a simple library.

Syntax

Composing Implicit Conversions in Traits

Implicit syntax conversions provided in publicly-exposed traits should be marked final
so that any composition of the traits provides conversions that can all be inlined.

Ops Classes

Ops classes should be marked final and extend AnyVal, to take full advantage of inlining and prevent unnecessary allocations.

The most notable exception is the case where all of the ops in the class are provided by zero-cost macros anyway,
for example with Simulacrum.

Partially-Applied Type

In Scala, when there are multiple type parameters in a function, either scalac infers all type parameters or the user has to
specify all of them. Often we have functions where there are one or more types that are inferable but not all of them. For example, there is helper function in OptionT that creates an OptionT[F, A] from an A. It could be written as:

scala mdoc:silent
import cats._
import cats.syntax.all._
import cats.data.OptionT
scala mdoc
def pure[F[_], A](a: A)(implicit F: Applicative[F]): OptionT[F, A] =
  OptionT(F.pure(Some(a)))


pure[List, Int](1)

Note that the type A should've been given by the a: A argument, but since scalac cannot infer F[_], the user still has to specify all type params.
In Сats, we use a technique described in
Rob Norris’s Kinda-Curried Type Parameters to overcome this restriction of scala inference. Here is a version of the pure using this technique in Сats.

scala
package cats.data

object OptionT {

  private[data] final class PurePartiallyApplied[F[_]](val dummy: Boolean = true ) extends AnyVal {
    def apply[A](value: A)(implicit F: Applicative[F]): OptionT[F, A] =
      OptionT(F.pure(Some(value)))
  }

  def pure[F[_]]: PurePartiallyApplied[F] = new PurePartiallyApplied[F]
}

We introduced an intermediate or, as the name suggested, type parameter partially applied type PurePartiallyApplied to divide the function into two steps: the first step is a construction of the partially applied type, for which the type F[_] is given by the user; the second step is the apply method inside partially applied type, for which the A can be inferred from the argument. Now we can write:

scala mdoc
OptionT.pure[List](1)

The user doesn't need to specify the type A which is given by the parameter.

You probably noticed that there is a val dummy: Boolean in the PurePartiallyApplied class. This is a trick we used
to make this intermediate class a Value Class so that there is no cost of allocation, i.e. at runtime, it doesn't create an instance of PurePartiallyApplied. We also hide this partially applied class by making it package private and placing it inside an object.

Implicit naming

In a widely-used library it's important to minimize the chance that the names of implicits will be used by others and
therefore name our implicits according to the following rules:

  • Implicits should start with "cats" followed by the package name (where the instance is defined).
  • If the package contains instances leave instances out.
  • The type and the type class should be mentioned in the name.
  • If the instance is for multiple type classes, use InstancesFor instead of a type class name.
  • If the instance is for a standard library type add Std after the package. i.e. catsStdShowForVector and catsKernelStdGroupForTuple.

As an example, an implicit instance of Monoid for List defined in the package Kernel should be named catsKernelStdMonoidForList.

This rule is relatively flexible. Use what you see appropriate. The goal is to maintain uniqueness and avoid conflicts.

Implicit instance priority

When there are multiple instances provided implicitly, if the type class of them are in the same inheritance hierarchy,
the instances need to be separated out into different abstract class/traits so that they don't conflict with each other. The names of these abstract classes/traits should be numbered with a priority with 0 being the highest priority. The abstract classes/trait
with higher priority inherits from the ones with lower priority. The most specific (whose type class is the lowest in the hierarchy) instance should be placed in the abstract class/ trait with the highest priority. Here is an example.

scala
trait Functor[F[_]]


trait Monad[F[_]] extends Functor

...
object Kleisli extends KleisliInstance0

abstract class KleisliInstance0 extends KleisliInstance1 {
  implicit def catsDataMonadForKleisli[F[_], A]: Monad[Kleisli[F, A, *]] = ...
}

abstract class KleisliInstance1 {
  implicit def catsDataFunctorForKleisli[F[_], A]: Functor[Kleisli[F, A, *]] = ...
}

Type classes that ONLY define laws.

We can introduce new type classes for the sake of adding laws that don't apply to the parent type class, e.g. CommutativeSemigroup and
CommutativeArrow.

Applicative instances for monad transformers

We explicitly don't provide an instance of Applicative for e.g. EitherT[F, String, *] given an Applicative[F].
An attempt to construct one without a proper Monad[F] instance would be inconsistent in ap with the provided Monad instance
for EitherT[F, String, *]. Such an instance will be derived if you use Nested instead:

scala
import cats._, cats.data._, cats.implicits._

val a = EitherT(List(Left("err"), Right(1)))
val x = (a *> a).value
> x: List[Either[String, Int]] = List(Left("err"), Left("err"), Right(1))

val y = (a.toNested *> a.toNested).value
> y: List[Either[String, Int]] = List(Left("err"), Left("err"), Left("err"), Right(1))

x === y
> false

Classes extending AnyVal

AnyVal-extending class constructor parameters must be marked as private.


Imports (`docs/imports.md`)

Imports

The easiest approach to Сats imports is to import everything that's commonly needed:

scala mdoc:reset:silent
import cats._
import cats.data._
import cats.syntax.all._

The cats._ import brings in quite a few type classes (similar to interfaces) such as Monad, Semigroup, and Foldable. Instead of the entire cats package, you can import only the types that you need, for example:

scala mdoc:reset:silent
import cats.Monad
import cats.Semigroup
import cats.Foldable

The cats.data._, import brings in data structures such as Validated and State. Instead of the entire cats.data package, you can import only the types that you need, for example:

scala mdoc:reset:silent
import cats.data.Validated
import cats.data.State

The cats.syntax.all._ import adds syntax enrichment onto certain types to provide some handy methods such as right-biased Either combinators:

scala mdoc:reset
import cats.syntax.all._

// Сats adds right-biased combinators to the standard library's Either
val e: Either[String, Int] = Right(3)
e.map(_ + 1)

// cats adds an orEmpty method to the standard library's Option
val o: Option[String] = None
o.orEmpty

If you'd like to import à la carte, you can do so, by importing from cats.syntax for syntax enrichment.
For example, if you'd like to import the Semigroup syntax:

scala mdoc:reset
import cats.syntax.semigroup._

"Hello, " |+| "World!"

The import adds the |+| syntax.

Note: Beware that if you import a type class instance or its syntax twice, you will receive conflicting implicits with a less than helpful error message.
This usually happens when importing different type classes in the same hierarchy or when importing syntax enrichment for all type classes using cats.syntax.all._ or cats.implicits._ together with a more specific import like cats.syntax.option._ or cats.instances.either._.
Below is an example of this phenomenon:

scala mdoc:reset:silent:fail
import cats.syntax.all._

1 |+| 2

import cats.syntax.semigroup._

3 |+| 5 // error: value |+| is not a member of Int

Compilation fails on the second invocation of |+| because we now have conflicting implicits from Semigroup.


Jump Start Guide (`docs/jump_start_guide.md`)

{% laika.title = Jump Start Guide %}

Introduction

This jump start guide barely scratches the surface of what Cats can do, but instead provides a concise hands-on introduction to the patterns you're most likely to take advantage of in your Scala project.
If you're using the constructs like Future,
Option or
Either on a daily basis,
it's very likely that Cats can simplify and improve the readability of your code.

Please refer to the wiki on GitHub for guidelines on how to add the library to your project dependencies.
We are sticking to version 2.13.0 in the entire post.

Let's go through the library package-wise, looking at the syntax available in each package.

Option Helpers

scala mdoc:silent
import cats.syntax.all._

Importing this package enables obj.some syntax — equivalent to Some(obj).
The only real difference is that the value is already upcast to Option[T] from Some[T].

Using obj.some instead of Some(obj) can sometimes e.g. improve readability when you need to provide dummy implementation for service methods for the purpose of testing.
For example, if you put the following implicit class into the scope:

scala mdoc:silent
import scala.concurrent.Future

implicit class ToFutureSuccessful[T](obj: T) {
  def asFuture: Future[T] = Future.successful(obj)
}

then you can use the chained syntax shown below:

scala mdoc:silent
class Account { /* ... */ }

trait AccountService {
  def getAccountById(id: Int): Future[Option[Account]]
}

class DummyAccountServiceImpl extends AccountService {

  def dummyAccount: Account = ???

  /* ... */
  override def getAccountById(id: Int): Future[Option[Account]] = dummyAccount.some.asFuture
  /* ... */
}

That's more readable than Future.successful(Some(dummyAccount)), especially if this pattern repeats frequently.
Chaining .some.asFuture at the end rather than putting it at the front also helps focus on what's actually being returned rather than on the expected wrapper type.

none[T], in turn, is shorthand for Option.empty[T] which is just None, but already upcast from None.type to Option[T].
Providing a more specialized type sometimes helps the Scala compiler properly infer the type of expressions containing None.

Either Helpers

scala mdoc:silent
import cats.syntax.all._

obj.asRight is Right(obj), obj.asLeft is Left(obj).
In both cases the type of returned value is widened from Right or Left to Either.
Just as was the case with .some, these helpers are handy to combine with .asFuture to improve readability:

scala mdoc:silent
case class User(accountId: Long) { /* ... */ }

trait UserService {
  def ensureUserExists(id: Int): Future[Either[Exception, User]]
}

class UserServiceSpec extends UserService {

  def dummyUser: User = ???

  /* ... */
  override def ensureUserExists(id: Int): Future[Either[Exception, User]] = dummyUser.asRight.asFuture // instead of Future.successful(Right(dummyUser))
  /* ... */
}

Either.fromOption(option: Option[A], ifNone: => E), in turn, is a useful helper for converting an Option to an Either.
If the provided option is Some(x), it becomes Right(x).
Otherwise it becomes Left with the provided ifNone value inside.

Tuples

The apply package provides (..., ..., ...).mapN syntax, which allows for an intuitive construct for applying a function that takes more than one parameter to multiple effectful values (like futures).

Let's say we have 3 futures, one of type Int, one of type String, one of type User and a method accepting three parameters — Int, String and User.

scala mdoc:silent
import scala.concurrent.ExecutionContext.Implicits.global

class ProcessingResult { /* ... */ }

def intFuture: Future[Int] = { /* ... */ ??? }
def stringFuture: Future[String] = { /* ... */ ??? }
def userFuture: Future[User] = { /* ... */ ??? }

def process(value: Int, contents: String, user: User): ProcessingResult = { /* ... */ ??? }

Our goal is to apply the function to the values computed by those 3 futures.
With apply syntax this becomes very easy and concise:

scala mdoc:silent
import cats.syntax.all._

def processAsync: Future[ProcessingResult] = {
  (intFuture, stringFuture, userFuture).mapN {
    (value, contents, user) =>
      process(value, contents, user)
  }
}

By default the implicit instances (namely, Functor[Future] and
Semigroupal[Future]) required for mapN to work properly are always visible. They are present in the respective companion objects of the instances and hence we do not need to import them explicitly.

This above idea can be expressed even shorter, just:

scala mdoc:silent
def processAsync2: Future[ProcessingResult] = (intFuture, stringFuture, userFuture).mapN(process)

If any of the chained futures fails, the resulting future will also fail with the same exception as the first failing future in the chain (this is fail-fast behavior).

What's important, all futures will run in parallel, as opposed to what would happen in a for comprehension:

scala mdoc:silent
def processAsync3: Future[ProcessingResult] = {
  for {
    value <- intFuture
    contents <- stringFuture
    user <- userFuture
  } yield process(value, contents, user)
}

In the above snippet (which under the hood translates to flatMap and map calls), stringFuture will not run until intFuture is successfully completed,
and in the same way userFuture will be run only after stringFuture completes.
But since the computations are independent of one another, it's perfectly viable to run them in parallel with mapN instead.

Traversing

scala mdoc:silent
import cats.syntax.all._

`traverse`

If you have an instance obj of type F[A] that can be mapped over (like Future) and a function fun of type A => G[B], then calling obj.map(fun) would give you F[G[B]].
In many common real-life cases, like when F is Option and G is Future, you would get Option[Future[B]], which most likely isn't what you wanted.

traverse comes as a solution here.
If you call traverse instead of map, like obj.traverse(fun), you'll get G[F[A]], which will be Future[Option[B]] in our case; this is much more useful and easier to process than Option[Future[B]].

scala mdoc:silent
def updateUser(user: User): Future[User] = { /* ... */ ??? }

def updateUsers(users: List[User]): Future[List[User]] = {
  users.traverse(updateUser)
}

As a side note, there is also a dedicated method Future.traverse in the Future companion object,
but the Cats version is far more readable and can easily work on any structure for which certain type classes are available.

`sequence`

sequence represents an even simpler concept: it can be thought of as simply swapping the types from F[G[A]] to G[F[A]] without even mapping the enclosed value like traverse does.

scala mdoc:silent
val foo: List[Future[String]] = List(Future("hello"), Future("world"))
val bar = foo.sequence // will have Future[List[String]] type

obj.sequence is in fact implemented in Cats as obj.traverse(identity).

On the other hand, obj.traverse(fun) is roughly equivalent to obj.map(fun).sequence.

`flatTraverse`

If you have an obj of type F[A] and a function fun of type A => G[F[B]], then doing obj.map(f) yields result of type F[G[F[B]]] — very unlikely to be what you wanted.

Traversing the obj instead of mapping helps a little — you'll get G[F[F[B]] instead.
Since G is usually something like Future and F is List or Option, you would end up with Future[Option[Option[A]] or Future[List[List[A]]] — a bit awkward to process.

scala mdoc:silent
lazy val valueOpt: Option[Int] = { /* ... */ ??? }
def compute(value: Int): Future[Option[Int]] = { /* ... */ ??? }
def computeOverValue: Future[Option[Option[Int]]] = valueOpt.traverse(compute) // has type Future[Option[Option[Int]]], not good

The solution could be to map the result with a _.flatten call like:

scala mdoc:silent
def computeOverValue2: Future[Option[Int]] = valueOpt.traverse(compute).map(_.flatten)

and this way you'll get the desired type G[F[B]] at the end.

However, there is a neat shortcut for this called flatTraverse:

scala mdoc:silent
def computeOverValue3: Future[Option[Int]] = valueOpt.flatTraverse(compute)

and that solves our problem for good.

Monad Transformers

OptionT

scala mdoc:silent
import cats.data.OptionT

An instance of OptionT[F, A] can be thought of as a wrapper over F[Option[A]]
which adds a couple of useful methods specific to nested types that aren't available in F or Option itself.
Most typically, your F will be Future (or sometimes slick's DBIO, but this requires having an implementation of Cats type classes like Functor or Monad for DBIO).
Wrappers such as OptionT are generally known as monad transformers.

A quite common pattern is mapping the inner value stored inside an instance of F[Option[A]] to an instance of F[Option[B]] with a function of type A => B.
This can be done with rather verbose syntax like:

scala mdoc:silent
lazy val resultFuture: Future[Option[Int]] = ???

def mappedResultFuture: Future[Option[String]] = resultFuture.map { maybeValue =>
  maybeValue.map { value =>
    // Do something with the value and return String
    ???
  }
}

With the use of OptionT, this can be simplified as follows:

scala mdoc:silent
def mappedResultFuture2: OptionT[Future, String] = OptionT(resultFuture).map { value =>
  // Do something with the value and return String
  ???
}

The above map will return a value of type OptionT[Future, String].

To get the underlying Future[Option[String]] value, simply call .value on the OptionT instance.
It's also a viable solution to fully switch to OptionT[Future, A] in method parameter/return types and completely (or almost completely) ditch Future[Option[A]] in type declarations.

There are several ways to construct an OptionT instance.
The method headers in the table below are slightly simplified: the type parameters and type classes required by each method are skipped.

Method Takes Returns
OptionT.apply or OptionT(...) F[Option[A]] OptionT[F, A]
OptionT.fromOption Option[A] OptionT[F, A]
OptionT.liftF F[A] OptionT[F, A]
OptionT.pure A OptionT[F, A]

In production code you'll most commonly use the OptionT(...) syntax in order to wrap an instance of Future[Option[A]] into OptionT[F, A].
The other methods, in turn, prove useful to set up OptionT-typed dummy values in unit tests.

We have already come across one of OptionT's methods, namely map.
There are several other methods available and they mostly differ by the signature of the function they accept as the parameter.
As was the case with the previous table, the expected type classes are skipped.

Method Takes Returns
map[B] A => B OptionT[F, B]
subflatMap[B] A => Option[B] OptionT[F, B]
semiflatMap[B] A => F[B] OptionT[F, B]
flatMapF[B] A => F[Option[B]] OptionT[F, B]
flatMap[B] A => OptionT[F, B] OptionT[F, B]

In practice, you're most likely to use map and semiflatMap.

As is always the case with flatMap and map, you can use it not only explicitly, but also under the hood in for comprehensions, as in the example below:

scala mdoc:silent
class Money { /* ... */ }

def findUserById(userId: Long): OptionT[Future, User] = { /* ... */ ??? }

def findAccountById(accountId: Long): OptionT[Future, Account] = { /* ... */ ??? }

def getReservedFundsForAccount(account: Account): OptionT[Future, Money] = { /* ... */ ??? }

def getReservedFundsForUser(userId: Long): OptionT[Future, Money] = for {
  user <- findUserById(userId)
  account <- findAccountById(user.accountId)
  funds <- getReservedFundsForAccount(account)
} yield funds

The OptionT[Future, Money] instance returned by getReservedFundsForUser will enclose a None value if any of the three composed methods returns an OptionT corresponding to None.
Otherwise, if the result of all three calls contains Some, the final outcome will also contain Some.

EitherT

scala mdoc:silent
import cats.data.EitherT

EitherT[F, A, B] is the monad transformer for Either — you can think of it as a wrapper over a F[Either[A, B]] value.

Just as in the above section, I simplified the method headers, skipping type parameters or their context bounds and lower bounds.

Let's have a quick look at how to create an EitherT instance:

Method Takes Returns
EitherT.apply or EitherT(...) F[Either[A, B]] EitherT[F, A, B]
EitherT.fromEither Either[A, B] EitherT[F, A, B] (wraps the provided Either value into F)
EitherT.right or EitherT.liftF F[B] EitherT[F, A, B] (wraps value inside F[B] into Right)
EitherT.left F[A] EitherT[F, A, B] (wraps value inside F[B] into Left)
EitherT.pure A EitherT[F, A, B] (wraps value into Right and then into F)

Another useful way to construct an EitherT instance is to use OptionT's methods toLeft and toRight:

scala mdoc:silent
abstract class BaseException(message: String) extends Exception(message)

case class UserNotFoundException(message: String) extends BaseException(message)

def getUserById(userId: Int): Future[Option[User]] = { /* ... */ ??? }

def ensureUserExists(userId: Int): EitherT[Future, BaseException, User] = {
  OptionT(getUserById(userId))
    .toRight(left = UserNotFoundException(s"user not found, userId=$userId"))
}

toRight is pretty analogous to the method Either.fromOption mentioned before: just as fromOption built an Either from an Option, toRight creates an EitherT from an OptionT.
If the original OptionT stores Some value, it will be wrapped into Right; otherwise the value provided as the left parameter will be wrapped into a Left.
To provide the left value within the monad, there is corresponding toRightF method.

toLeft is toRight's counterpart which wraps the Some value into Left and transforms None into Right enclosing the provided right value.
This is less commonly used in practice, but can serve e.g. for enforcing uniqueness checks in code.
We return Left if the value has been found, and Right if it doesn't yet exist in the system.

The methods available in EitherT are pretty similar to those we've seen in OptionT, but there are some notable differences.

You might get into some confusion at first when it comes to e.g. map.
In the case of OptionT, it was pretty obvious what should be done: map should go over the Option enclosed within Future, and then map the enclosed Option itself.
This is slightly less obvious in case of EitherT: should it map over both Left and Right values, or only the Right value?

The answer is that EitherT is right-biased, therefore plain map actually deals with the Right value.
This is unlike Either in the Scala standard library up to 2.11, which is in turn unbiased: there's no map available in Either, only for its left and right projections.

Having said that, let's take a quick look at the right-biased methods that EitherT offers:

Method Takes Returns
map[D] B => D EitherT[F, A, D]
subflatMap[D] B => Either[A, D] EitherT[F, A, D]
semiflatMap[D] B => F[D] EitherT[F, A, D]
flatMapF[D] B => F[Either[A, D]] EitherT[F, A, D]
flatMap[D] B => EitherT[F, A, D] EitherT[F, A, D]

As a side note, there are also certain methods in EitherT (that you're likely to need at some point) which map over the Left value, like leftMap, or over both Left and Right values, like fold or bimap.

EitherT is very useful for fail-fast chained verifications:

scala mdoc:silent
case class Item(state: String)
class ItemOrder  { /* ... */ }

case class ItemNotFoundException(message: String) extends BaseException(message)
case class InvalidItemStateException(message: String) extends BaseException(message)

def getItemById(itemId: Int): Future[Option[Item]] = { /* .. */ ??? }

def ensureItemExists(itemId: Int): EitherT[Future, BaseException, Item] = {
  OptionT(getItemById(itemId))
    .toRight(ItemNotFoundException(s"item not found, itemId = $itemId"))
}

def ensureItemStateIs(actual: String, expected: String): EitherT[Future, BaseException, Unit] = {
  // Returns a Unit value wrapped into Right and then into Future if condition is true,
  // otherwise the provided exception wrapped into Left and then into Future.
  EitherT.cond(actual == expected, (), InvalidItemStateException(s"actual=$actual, expected=$expected"))
}

def placeOrderForItem(userId: Int, itemId: Int, count: Int): Future[ItemOrder] = { /* ... */ ??? }

def buyItem(userId: Int, itemId: Int, count: Int): EitherT[Future, BaseException, ItemOrder] = {
  for {
    user <- ensureUserExists(userId)
    item <- ensureItemExists(itemId)
    _ <- ensureItemStateIs(item.state, "AVAILABLE_IN_STOCK")
    // EitherT.liftF is necessary to make EitherT[Future, BaseException, ItemOrder] out of Future[ItemOrder]
    placedOrder <- EitherT.liftF(placeOrderForItem(userId, itemId, count))
  } yield placedOrder
}

In the above example, we're running various checks against the item one by one.
If any of the checks fails, the resulting EitherT will contain a Left value.
Otherwise, if all of the checks yield a Right (of course we mean a Right wrapped into an EitherT), then the final outcome will also contain Right.
This is a fail-fast behavior: we're effectively stopping the for comprehension flow at the first Left-ish result.

If you're instead looking for validation that accumulates the errors (e.g. when dealing with user-provided form data), cats.data.Validated may be a good choice.

Common issues

The Cats type class instances for standard library types are available in implicit scope and hence no longer have to be imported. If anything doesn't compile as expected, first make sure all the required Cats syntax implicits are in the scope — try importing cats.syntax.all._ and see if the problem persists. The only exception is here is Cat's own Order and PartialOrder type classes which are available by importing cats.implicits._.
As mentioned before, though, it's better to use narrow imports, but if the code doesn't compile it's sometimes worth just importing the entire library to check if it solves the problem.

If you're using Futures, make sure to provide an implicit ExecutionContext in the scope, otherwise Cats won't be able to infer implicit instances for Future's type classes.

IntelliJ sometimes reports errors in Cats-loaded code even though the source passes under scalac.
One such example are invocations of the methods of cats.data.Nested class, which compile correctly under scalac, but don't type check under IntelliJ's presentation compiler.
It should work without trouble under Scala IDE, though.

As an advice for your future learning: the Applicative type class, despite it's key significance in functional programming, comes slightly difficult to understand.
In my opinion it's much less intuitive than Functor or Monad, even though it actually stands right between Functor and Monad in the inheritance hierarchy.
The best approach to grasp Applicative is to first understand how product (which transforms an F[A] and F[B] to an F[(A, B)]) works rather than focus on the somewhat exotic ap operation itself.


Motivations (`docs/motivations.md`)

{% laika.title = Motivations %}

Approachability

As this library evolves, we are placing a lot of emphasis on trying to
make decisions which will help keep this library approachable for
people new to the concepts in this library. We are collecting
anecdotes from successes and failures we have experienced in the past
in trying to teach others about these concepts, and trying to make
decisions which will help ease the process of getting acquainted to
the library for a newcomer. If you have any feedback for us in this
regard, we would love to hear from you. See the Contributing
page
to find out ways to give us feedback.

Modularity

We are trying to make the library modular. It will have a tight
core which will contain only the type classes,
the bare minimum of data structures that are needed to support
them, and type class instances for those data structures and standard
library types.

Documentation

We feel that having lots of documentation is a very important goal for
our project. It will be a big win towards our goal of
approachability. We will strive to have the code well documented, we
will strive to have lots of documentation external to the code, and we
will strive to have a large corpus of compiler verified examples of
how the software can be used.

Writing documentation is a huge part of developing software, and one
that is often neglected. It is also a very easy way to get started
with contributing to the project.

Efficiency

Although unfortunately there are times when programming only with
pure functions and writing efficient code in Scala can be at odds, we
are attempting to do our best at keeping our library as efficient as
we can without making unnecessary sacrifices of purity and
usability. Where sacrifices have to be made, we will strive to make
these obvious, and will keep them well documented.


Nomenclature (`docs/nomenclature.md`)

Glossary

This is a catalogue of the major functions, type classes, and data types in Cats. It serves as a bird's-eye view of each class capabilities. It is also intended as a go-to reference for Cats users, who may not recall the answer to questions like these:

  • What is the difference between unit and void?
  • To discard the first value and keep only the first effect, is it <* or *>?
  • How do I make a computation F[A] fail by checking a condition on the value?

The signatures and type-classes have been simplified, are described below. If you want a printable version, you can also check out this cats-cheatsheet.

WARNING: this page is written manually, and not automatically generated, so many things may be missing. If you find a mistake, or addition, please submit a PR following the guidelines below.

Type-Classes over an `F[_]`

Functor

Type Method Name Notes
F[A] => F[Unit] void
F[A] => B => F[B] as
F[A] => (A => B) => F[B] map
F[A] => (A => A1) => F[A1]) mapOrKeep A1 >: A, the (A => A1) is a PartialFunction
F[A] => (A => B) => F[(A,B)] fproduct
F[A] => (A => B) => F[(B,A)] fproductLeft
F[A] => B => F[(B, A)] tupleLeft
F[A] => B => F[(A, B)] tupleRight
(A => B) => (F[A] => F[B]) lift

Apply

Type Method Name Symbol
F[A] => F[B] => F[A] productL <*
F[A] => F[B] => F[B] productR *>
F[A] => F[B] => F[(A,B)] product
F[A => B] => F[A] => F[B] ap <*>
F[A => B => C] => F[A] => F[B] => F[C] ap2
F[A] => F[B] => (A => B => C) => F[C] map2

Applicative

Type Method Name Notes
A => F[A] pure
=> F[Unit] unit
Boolean => F[Unit] => F[Unit] whenA Performs effect iff condition is true
unlessA Adds effect iff condition is false

FlatMap

Type Method Name
F[F[A]] => F[A] flatten
F[A] => (A => F[B]) => F[B] flatMap
F[A] => (A => F[B]) => F[(A,B)] mproduct
F[Boolean] => F[A] => F[A] => F[A] ifM
F[A] => (A => F[B]) => F[A] flatTap

FunctorFilter

Type Method Name Notes
F[A] => (A => Boolean) => F[A] filter
F[A] => (A => Option[B]) => F[B] mapFilter
F[A] => (A => B) => F[B] collect The A => B is a PartialFunction
F[Option[A]] => F[A] flattenOption

ApplicativeError

The source code of Cats uses the E type variable for the error type.

Type Method Name Notes
E => F[A] raiseError
F[A] => F[Either[E,A]] attempt
F[A] => (E => A) => F[A] handleError
F[A] => (E => F[A]) => F[A] handleErrorWith
F[A] => (E => A) => F[A] recover The E => A is a PartialFunction.
F[A] => (E => F[A]) => F[A] recoverWith The E => F[A] is a PartialFunction.
F[A] => (E => F[Unit]) => F[A] onError The E => F[Unit] is a PartialFunction.
Either[E,A] => F[A] fromEither
Option[A] => E => F[A] liftFromOption

MonadError

Like the previous section, we use the E for the error parameter type.

Type Method Name Notes
F[A] => E => (A => Boolean) => F[A] ensure
F[A] => (A => E) => (A => Boolean) => F[A] ensureOr
F[A] => (E => E) => F[A] adaptError The E => E is a PartialFunction.
F[Either[E,A]] => F[A] rethrow

UnorderedFoldable

Type Method Name Constraints
F[A] => Boolean isEmpty
F[A] => Boolean nonEmpty
F[A] => Long size
F[A] => (A => Boolean) => Boolean forall
F[A] => (A => Boolean) => Boolean exists
F[A] => A unorderedFold A: CommutativeMonoid
F[A] => (A => B) => B unorderedFoldMap B: CommutativeMonoid

Foldable

Type Method Name Constraints
F[A] => A fold A: Monoid
F[A] => B => ((B,A) => B) => B foldLeft
F[A] => (A => B) => B foldMap B: Monoid
F[A] => (A => G[B]) => G[B] foldMapM G: Monad and B: Monoid
F[A] => (A => B) => Option[B] collectFirst The A => B is a PartialFunction
F[A] => (A => Option[B]) => Option[B] collectFirstSome
F[A] => (A => G[B]) => G[Unit] traverse_ G: Applicative
F[G[A]] => G[Unit] sequence_ G: Applicative
F[A] => (A => Either[B, C]) => (F[B], F[C]) partitionEither G: Applicative

Reducible

Type Method Name Constraints
F[A] => ((A,A) => A) => A reduceLeft
F[A] => A reduce A: Semigroup

Traverse

Type Method Name Constraints
F[G[A]] => G[F[A]] sequence G: Applicative
F[A] => (A => G[B]) => G[F[B]] traverse G: Applicative
F[A] => (A => G[F[B]]) => G[F[B]] flatTraverse F: FlatMap and G: Applicative
F[G[F[A]]] => G[F[A]] flatSequence G: Applicative and F: FlatMap
F[A] => F[(A,Int)] zipWithIndex
F[A] => ((A,Int) => B) => F[B] mapWithIndex
F[A] => ((A,Int) => G[B]) => G[F[B]] traverseWithIndexM F: Monad

SemigroupK

Type Method Name Constraints
F[A] => F[A] => F[A] combineK
F[A] => Int => F[A] combineNK
F[A] => F[B] => F[Either[A, B]] sum F: Functor
IterableOnce[F[A]] => Option[F[A]] combineAllOptionK

MonoidK

Type Method Name Constraints
F[A] empty
F[A] => Boolean isEmpty
IterableOnce[F[A]] => F[A] combineAllK

Alternative

Type Method Name Constraints
F[G[A]] => F[A] unite F: FlatMap and G: Foldable
F[G[A, B]] => (F[A], F[B]) separate F: FlatMap and G: Bifoldable
F[G[A, B]] => (F[A], F[B]) separateFoldable F: Foldable and G: Bifoldable
Boolean => F[Unit] guard
IterableOnce[A] => F[A] fromIterableOnce
G[A] => F[A] fromFoldable G: Foldable

NonEmptyAlternative

Type Method Name Constraints
A => F[A] => F[A] prependK
F[A] => A => F[A] appendK

Transformers

Constructors and wrappers

Data Type is an alias or wrapper of
OptionT[F[_], A] F[Option[A]]
EitherT[F[_], A, B] F[Either[A,B]
Kleisli[F[_], A, B] A => F[B]
Reader[A, B] A => B
ReaderT[F[_], A, B] Kleisli[F, A, B]
Writer[A, B] (A,B)
WriterT[F[_], A, B] F[(A,B)]
Tuple2K[F[_], G[_], A] (F[A], G[A])
EitherK[F[_], G[_], A] Either[F[A], G[A]]
FunctionK[F[_], G[_]] F[X] => G[X] for every X
F ~> G Alias of FunctionK[F, G]

OptionT

For convenience, in these types we use the symbol OT to abbreviate OptionT.

Type Method Name Constraints
=> OT[F, A] none F: Applicative
A => OT[F, A] some or pure F: Applicative
F[A] => OT[F, A] liftF F: Functor
Boolean => F[A] => OT[F, A] whenF F: Applicative
F[Boolean] => F[A] => OT[F, A] whenM F: Monad
OT[F, A] => F[Option[A]] value
OT[F, A] => A => Boolean => OT[F, A] filter F: Functor
OT[F, A] => A => F[Boolean] => OT[F, A] filterF F: Monad
OT[F, A] => (A => B) => OT[F, B] map F: Functor
OT[F, A] => (F ~> G) => OT[G, B] mapK
OT[F, A] => (A => Option[B]) => OT[F, B] mapFilter F: Functor
OT[F, A] => B => (A => B) => F[B] fold or cata
OT[F, A] => (A => OT[F, B]) => OT[F,B] flatMap
OT[F, A] => (A => F[Option[B]]) => OT[F,B] flatMapF F: Monad
OT[F, A] => A => F[A] getOrElse F: Functor
OT[F, A] => F[A] => F[A] getOrElseF F: Monad
OT[F, A] => OT[F, A] => OT[F, A]

EitherT

Here, we use ET to abbreviate EitherT; and we use A and B as type variables for the left and right sides of the Either.

Type Method Name Constraints
A => ET[F, A, B] leftT F: Applicative
B => ET[F, A, B] rightT F: Applicative
pure F: Applicative
F[A] => ET[F, A, B] left F: Applicative
F[B] => ET[F, A, B] right F: Applicative
liftF F: Applicative
Either[A, B] => ET[F, A, B] fromEither F: Applicative
Option[B] => A => ET[F, A, B] fromOption F: Applicative
F[Option[B]] => A => ET[F, A, B] fromOptionF F: Functor
F[Option[B]] => F[A] => ET[F, A, B] fromOptionM F: Monad
Boolean => B => A => ET[F, A, B] cond F: Applicative
ET[F, A, B] => (A => C) => (B => C) => F[C] fold F: Functor
ET[F, A, B] => ET[F, B, A] swap F: Functor
ET[F, A, A] => F[A] merge

Kleisli (or ReaderT)

Here, we use Ki as a short-hand for Kleisli.

Type Method Name Constraints
Ki[F, A, B] => (A => F[B]) run
Ki[F, A, B] => A => F[B] apply
A => Ki[F, A, A] ask F: Applicative
B => Ki[F, A, B] pure F: Applicative
F[B] => Ki[F, A, B] liftF
Ki[F, A, B] => (C => A) => Ki[F, C, B] local
Ki[F, A, B] => Ki[F, A, A] tap
Ki[F, A, B] => (B => C) => Ki[F, A, C] map
Ki[F, A, B] => (F ~> G) => Ki[G, A, B] mapK
Ki[F, A, B] => (F[B] => G[C]) => Ki[F, A, C] mapF
Ki[F, A, B] => Ki[F, A, F[B]] lower

Type Classes for types `F[_, _]`

Bifunctor

Type Method Name
F[A,B] => (A => C) => F[C,B] leftMap
F[A,B] => (B => D) => F[A,D] .rightFunctor and .map
F[A,B] => (A => C) => (B => D) => F[C,D] bimap

Profunctor

Type Method Name
F[A, B] => (B => C) => F[A, C] rmap
F[A, B] => (C => A) => F[C, B] lmap
F[A, B] => (C => A) => (B => D) => F[C,D] dimap

Strong Profunctor

Type Method Name
F[A, B] => F[(A,C), (B,C)] first
F[A, B] => F[(C,A), (C,B)] second

Compose, Category, Choice

Type Method Name Symbol
F[A, B] => F[C, A] => F[C, B] compose <<<
F[A, B] => F[B, C] => F[A, C] andThen >>>
=> F[A,A] id
F[A, B] => F[C, B] => F[Either[A, C], B] choice `
=> F[ Either[A, A], A] codiagonal

Arrow

Type Method Name Symbol
(A => B) => F[A, B] lift
F[A,B] => F[C,D] => F[(A,C), (B,D)] split ***
F[A,B] => F[A,C] => F[A, (B,C)] merge &&&

ArrowChoice

Type Method Name Symbol
F[A,B] => F[C,D] => F[Either[A, C], Either[B, D]] choose +++
F[A,B] => F[Either[A, C], Either[B, C]] left
F[A,B] => F[Either[C, A], Either[C, B]] right

Simplifications

Because Сats is a Scala library and Scala has many knobs and switches, the actual definitions and the implementations of the functions and type-classes in Сats can be a bit obfuscated at first. To alleviate this, in this glossary we focus on the plain type signatures of the method, and ignore many of the details from Scala. In particular, in our type signatures:

  • We use A,B,C for type variables of kind *, and F, G, H for type variables of a higher kind.
  • We write type signatures in currified form: parameters are taken one at a time, and they are separated with the arrow => operation. In Scala, a method's parameters may be split in several comma-separated lists.
  • We do not differentiate between methods from the type-class trait (e.g. trait Functor), or the companion object, or the syntax companion (implicit class).
  • For functions defined as method of the typeclass trait, we ignore the receiver object.
  • We ignore implicit parameters that represent type-class constraints; and write them on a side column instead.
  • We use A => B for both Function1[A, B] and PartialFunction[A, B] parameters, without distinction. We add a side note when one is a PartialFunction.
  • Some functions are defined through the Partially Applied Type Params pattern. We ignore this.
  • We ignore the distinction between by-name and by-value input parameters. We use the notation => A, without parameters, to indicate constant functions.
  • We ignore Scala variance annotations. We also ignore extra type parameters, which in some methods are added with a subtype-constraint, (e.g. B >: A). These are usually meant for flexibility, but we replace each one by its bound.

Resources For Learners (`docs/resources_for_learners.md`)

{% laika.title = Resources for Learners %}

Books

  • Functional Programming in Scala
    by Michael Pilquist, Rúnar Bjarnason, and Paul Chiusano - While this book does not
    specifically cover Cats, it is a great introduction to functional
    programming in Scala in general and covers some of the abstractions
    that can be found in Cats.
  • Scala with Cats
    by Noel Welsh and Dave Gurnell - The aims of this book are two-fold:
    to introduce monads, functors, and other functional programming patterns
    as a way to structure program design, and to explain how these
    concepts are implemented in Cats.

Tutorials

Example Projects

  • Scala Pet Store
    Demonstrates FP techniques while maintaining approachability for people with an OO background. Uses tagless final for the core domain, and popular Typelevel libraries including Cats, Http4s, Circe and Doobie.

Videos

  • Functional Structures in Scala
      by Michael Pilquist offers a series
    of lectures about basic functional structures.
  • Category Theory for Programmers
    by Bartosz Milewski is a series
    of category theory lectures oriented towards programmers.
    The code examples are written in Haskell and C++,
    but the course is designed for programmers of any background,
    even the ones without a strong maths knowledge.
  • Easy and efficient data validation with Cats by Daniela Sfregola this talk introduces Cats, and some of its most interesting components for data validation. In particular, we’ll discuss some options to achieve efficient and expressive data validation. We will also argue that, compared to other options in the language, Cats is particularly suited for the task thanks to its easy-to-use data types and more approachable syntax.
  • Cats by example by Thomas Höfer provides a beginner series on various datatypes from Cats.

Social network

  • @impurepics regularly tweet informative and kawaii educational pieces about Cats and FP in Scala.

Typeclasses (`docs/typeclasses.md`)

Type Classes

Type classes are a powerful tool used in functional programming to enable ad-hoc polymorphism, more commonly
known as overloading. Where many object-oriented languages leverage subtyping for polymorphic code, functional
programming tends towards a combination of parametric polymorphism (think type parameters, like Java generics)
and ad-hoc polymorphism.

Example: collapsing a list

The following code snippets show code that sums a list of integers, concatenates a list of strings, and unions a list
of sets.

scala mdoc:silent
def sumInts(list: List[Int]): Int = list.foldRight(0)(_ + _)

def concatStrings(list: List[String]): String = list.foldRight("")(_ ++ _)

def unionSets[A](list: List[Set[A]]): Set[A] = list.foldRight(Set.empty[A])(_ union _)

All of these follow the same pattern: an initial value (0, empty string, empty set) and a combining function
(+, ++, union). We'd like to abstract over this so we can write the function once instead of once for every type
so we pull out the necessary pieces into an interface.

scala mdoc:silent
trait Monoid[A] {
  def empty: A
  def combine(x: A, y: A): A
}

// Implementation for Int
val intAdditionMonoid: Monoid[Int] = new Monoid[Int] {
  def empty: Int = 0
  def combine(x: Int, y: Int): Int = x + y
}

The name Monoid is taken from abstract algebra which specifies precisely this kind of structure.

We can now write the functions above against this interface.

scala mdoc:silent
def combineAll[A](list: List[A], m: Monoid[A]): A = list.foldRight(m.empty)(m.combine)

Type classes vs. subtyping

The definition above takes an actual monoid argument instead of doing the usual object-oriented practice of using
subtype constraints.

scala mdoc:silent
// Subtyping
def combineAll[A <: Monoid[A]](list: List[A]): A = ???

This has a subtle difference with the earlier explicit example. In order to seed the foldRight with the empty value,
we need to get a hold of it given only the type A. Taking Monoid[A] as an argument gives us this by calling the
appropriate empty method on it. With the subtype example, the empty method would be on a value of type
Monoid[A] itself, which we are only getting from the list argument. If list is empty, we have no values to work
with and therefore can't get the empty value. Not to mention the oddity of getting a constant value from a non-static
object.


For another motivating difference, consider the simple pair type.

scala mdoc:silent
final case class Pair[A, B](first: A, second: B)

Defining a Monoid[Pair[A, B]] depends on the ability to define a Monoid[A] and Monoid[B], where the definition
is point-wise, i.e. the first element of the first pair combines with the first element of the second pair and the second element of the first pair combines with the second element of the second pair. With subtyping such a constraint would be encoded as something like

scala mdoc:silent:nest
final case class Pair[A <: Monoid[A], B <: Monoid[B]](first: A, second: B) extends Monoid[Pair[A, B]] {
  def empty: Pair[A, B] = ???

  def combine(x: Pair[A, B], y: Pair[A, B]): Pair[A, B] = ???
}

Not only is the type signature of Pair now messy but it also forces all instances of Pair to have a Monoid
instance, whereas Pair should be able to carry any types it wants and if the types happens to have a
Monoid instance then so would it. We could try bubbling down the constraint into the methods themselves.

scala mdoc:fail:nest
final case class Pair[A, B](first: A, second: B) extends Monoid[Pair[A, B]] {
  def empty(implicit eva: A <:< Monoid[A], evb: B <:< Monoid[B]): Pair[A, B] = ???

  def combine(x: Pair[A, B], y: Pair[A, B])(implicit eva: A <:< Monoid[A], evb: B <:< Monoid[B]): Pair[A, B] = ???
}

But now these don't conform to the interface of Monoid due to the implicit constraints.

Implicit derivation

Note that a Monoid[Pair[A, B]] is derivable given Monoid[A] and Monoid[B]:

scala mdoc:silent:nest
final case class Pair[A, B](first: A, second: B)

def deriveMonoidPair[A, B](A: Monoid[A], B: Monoid[B]): Monoid[Pair[A, B]] =
  new Monoid[Pair[A, B]] {
    def empty: Pair[A, B] = Pair(A.empty, B.empty)

    def combine(x: Pair[A, B], y: Pair[A, B]): Pair[A, B] =
      Pair(A.combine(x.first, y.first), B.combine(x.second, y.second))
  }

One of the most powerful features of type classes is the ability to do this kind of derivation automatically.
We can do this through Scala's implicit mechanism.

scala mdoc:reset-object
import cats.Monoid

object Demo {
  final case class Pair[A, B](first: A, second: B)

  object Pair {
    implicit def tuple2Instance[A, B](implicit A: Monoid[A], B: Monoid[B]): Monoid[Pair[A, B]] =
      new Monoid[Pair[A, B]] {
        def empty: Pair[A, B] = Pair(A.empty, B.empty)

        def combine(x: Pair[A, B], y: Pair[A, B]): Pair[A, B] =
          Pair(A.combine(x.first, y.first), B.combine(x.second, y.second))
      }
  }
}

We also change any functions that have a Monoid constraint on the type parameter to take the argument implicitly,
and any instances of the type class to be implicit.

scala mdoc:silent
implicit val intAdditionMonoid: Monoid[Int] = new Monoid[Int] {
  def empty: Int = 0
  def combine(x: Int, y: Int): Int = x + y
}

def combineAll[A](list: List[A])(implicit A: Monoid[A]): A = list.foldRight(A.empty)(A.combine)

Now we can also combineAll a list of Pairs as long as Pair's type parameters themselves have Monoid
instances.

scala mdoc:silent
implicit val stringMonoid: Monoid[String] = new Monoid[String] {
  def empty: String = ""
  def combine(x: String, y: String): String = x ++ y
}
scala mdoc
import Demo.{Pair => Paired}

combineAll(List(Paired(1, "hello"), Paired(2, " "), Paired(3, "world")))

A note on syntax

In many cases, including the combineAll function above, the implicit arguments can be written with syntactic sugar.

scala mdoc:compile-only
def combineAll[A : Monoid](list: List[A]): A = ???

While nicer to read as a user, it comes at a cost for the implementer.

scala mdoc:silent:reset
import cats.Monoid

// Defined in the standard library, shown for illustration purposes
// Implicitly looks in implicit scope for a value of type `A` and just hands it back
def implicitly[A](implicit ev: A): A = ev

def combineAll[A : Monoid](list: List[A]): A =
  list.foldRight(implicitly[Monoid[A]].empty)(implicitly[Monoid[A]].combine)

For this reason, many libraries that provide type classes provide a utility method on the companion object of the type
class, usually under the name apply, that skirts the need to call implicitly everywhere.

scala mdoc:silent:nest
object Monoid {
  def apply[A : Monoid]: Monoid[A] = implicitly[Monoid[A]]
}

def combineAll[A : Monoid](list: List[A]): A =
  list.foldRight(Monoid[A].empty)(Monoid[A].combine)

Laws

Conceptually, all type classes come with laws. These laws constrain implementations for a given
type and can be exploited and used to reason about generic code.

For instance, the Monoid type class requires that
combine be associative and empty be an identity element for combine. That means the following
equalities should hold for any choice of x, y, and z.

text
combine(x, combine(y, z)) = combine(combine(x, y), z)
combine(x, id) = combine(id, x) = x

With these laws in place, functions parametrized over a Monoid can leverage them for say, performance
reasons. A function that collapses a List[A] into a single A can do so with foldLeft or
foldRight since combine is assumed to be associative, or it can break apart the list into smaller
lists and collapse in parallel, such as

scala mdoc:silent
val list = List(1, 2, 3, 4, 5)
val (left, right) = list.splitAt(2)
scala mdoc
// Imagine the following two operations run in parallel
val sumLeft = combineAll(left)
val sumRight = combineAll(right)

// Now gather the results
val result = Monoid[Int].combine(sumLeft, sumRight)

Cats provides laws for type classes via the kernel-laws and laws modules which makes law checking
type class instances easy.

You can find out more about law testing here.

Type classes in Cats

From cats-infographic by @tpolecat.

Incomplete type class instances in cats

Originally from @hobwekiva

Type Functor Apply Applicative Monad MonoidK ApplicativeError MonadError CoflatMap Comonad Bimonad
Id[A] ✔ ✔ ✔ ✔ ✗ ✗ ✗ ✔ ✔ ✔
Eval[A] ✔ ✔ ✔ ✔ ✗ ✗ ✗ ✔ ✔ ✔
Option[A] ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✗ ✗
Const[K, A] ✔ ✔ (K:Monoid) ✔ ✗ ✗ ✗ ✗ ✗ ✗ ✗
Either[E, A] ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✗ ✗ ✗
List[A] ✔ ✔ ✔ ✔ ✔ ✗ ✗ ✔ ✗ ✗
NonEmptyList[A] ✔ ✔ ✔ ✔ ✗ ✗ ✗ ✔ ✔ ✔
Stream[A] ✔ ✔ ✔ ✔ ✔ ✗ ✗ ✔ ✗ ✗
Map[K, A] ✔ ✔ ✗ ✗ ✔ ✗ ✗ ✗ ✗ ✗
Validated[E, A] ✔ ✔ (E: Semigroup) ✔ ✗ ✗ ✔ (E: Semigroup) ✗ ✗ ✗ ✗
Reader[E, A] ✔ ✔ ✔ ✔ ✗ ✗ ✗ ✗ ✗ ✗
Writer[E, A] ✔ ✔ (E:Monoid) ✔ ✔ ✗ ✗ ✗ ✔ ✗ ✗

Further reading

  • [Returning the "Current" Type in Scala][fbounds]

[fbounds]: http://tpolecat.github.io/2015/04/29/f-bounds.html "Returning the "Current" Type in Scala"


TypelevelEcosystem (`docs/typelevelEcosystem.md`)

Typelevel Ecosystem

By sharing the same set of type classes, instances and data types provided by Cats, projects can speak the same “Cats language”, and integrate with each other with ease.

Libraries

Here you can find a comprehensive list of libraries and projects related to Typelevel:

Project Description
Mules In memory caching.
agitation Cooperative Cancelation for Cats Effect.
ancient-concurrent Cats Effect concurrent for cats-effect 0.10.
atto Friendly little text parsers.
bank Concurrent Vault Management.
canoe A purely functional library for building Telegram chatbots.
Cats Effect High-performance, asynchronous, composable framework for building real-world applications in a purely functional style.
cats-effect-testing Experimental integration between Cats Effect and testing frameworks.
cats-effect-time Java Time from Cats Effect.
cats-parse A parsing library for the Cats ecosystem.
cats-retry Composable retry logic for Cats and Cats Effect.
cats-scalacheck Cats typeclass instances for ScalaCheck.
cats-stm Software Transactional Memory for Cats Effect.
cats-time Cats typeclass instances for java.time.
chromaprint A Scala implementation of the Chromaprint/AcoustID audio fingerprinting algorithm, built with Fs2 streams / Cats Effect.
circe-fs2 Streaming JSON manipulation with Circe.
Circe Pure functional JSON library.
circuit Functional Circuit Breaker implementation.
ciris Lightweight, extensible, and validated configuration loading in Scala.
console4cats Console I/O for Cats Effect.
cormorant CSV handling library for FP.
coulomb-cats Cats typeclass instances for coulomb Quantity.
decline A composable command-line parser.
doobie-pool Doobie Pooling Mechanism in Pure FP.
doobie Pure functional JDBC built on Fs2.
droste Recursion schemes for Cats.
dsl-domains-cats The !-notation for creating Cats monadic expressions.
dynamapath Dynamic Path Parsing.
eff Functional effects and effect handlers (alternative to monad transformers).
epimetheus-circuit Prometheus Rejected Execution Metrics.
epimetheus-http4s Prometheus Http4s Metrics Middleware and Push Gateway Support.
epimetheus-log4cats Prometheus Logging Metrics.
epimetheus-redis4cats Prometheus Redis4cats Metrics.
epimetheus Prometheus Core Representations.
extruder Populate case classes from any data source.
fastparse-cats Cats Monad and Alternative instances for fastparse.
fd4s/fs2-kafka Functional Kafka Streams for Scala.
fetch Efficient data access to heterogeneous data sources.
finch Scala combinator api for building finagle http services.
fly4s A lightweight, simple and functional wrapper for Flyway using Cats Effect.
frameless Expressive types for Spark.
freestyle Pure functional framework for free and tagless final applications and libraries.
fs2-aws Fs2 streams to interact with AWS utilities.
fs2-blobstore Minimal, idiomatic, stream-based Scala interface for S3, GCS, SFTP and other key/value store implementations.
fs2-cassandra Cassandra bindings for Fs2.
fs2-columns A Chunk that uses Shapeless to store case class data column-wise.
fs2-cron Fs2 streams based on cron expressions.
fs2-crypto TLS support for Fs2.
fs2-data A set of data parsers and manipulation libraries for various formats for Fs2.
fs2-elastic Simple client for Elasticsearch.
fs2-ftp Simple client for Ftp/Ftps/Sftp using Fs2 and Cats Effect.
fs2-google-pubsub A Google Cloud Pub/Sub implementation using Fs2 and Cats Effect.
fs2-grpc GRPC implementation for Fs2 / Cats Effect.
fs2-http Http server and client library implemented in Fs2.
fs2-jms Java Messaging Service (JMS) connectors for Fs2 streams.
fs2-log Simple logging facade for Fs2.
fs2-mail Fully asynchronous Java non-blocking email client using Fs2.
fs2-mqtt A purely functional MQTT client library based on Fs2 and Cats Effect.
fs2-rabbit RabbitMQ stream-based client built on top of Fs2 and Cats Effect.
fs2-reactive-streams A reactive streams implementation for Fs2.
fs2-ssh A wrapper around Apache SSHD targeting Cats Effect and Fs2.
fs2-throttler Throttling for fs2 based on the token bucket algorithm.
fs2-zk Simple Apache Zookeeper bindings for Fs2.
Fs2 Functional streams for Scala (streaming I/O library).
fuuid-annotation Automatically create an inner Id tagged FUUID type with convenient methods for its creation.
fuuid Functional UUID's.
gato-parsec Generalized attoparsec with Cats.
github4s Wrapper around the GitHub API.
github Github Integration for Scala.
grafter Dependency-injection library using the Reader pattern.
graphite4s Lightweight graphite client.
gsheets4s Wrapper around the Google Sheets API.
hammock Purely functional HTTP client.
henkan Type safe conversion between case class instances with similar fields.
http4s Minimal, idiomatic Scala interface for HTTP services using Fs2.
iota Fast (co)product types with a clean syntax.
itto-csv Pure functional library for working with CSV.
jms4s A functional wrapper for jms
kafka4s Functional programming with Kafka and Scala.
kamon-monix Kamon Integration for Monix.
keysemaphore Keyed Semaphore implementation.
laserdisc LaserDisc is a(nother) Scala driver for Redis.
library.g8 Library Starter Template.
linebacker Thread pool management for Scala: Enabling functional blocking where needed.
log4cats-log4s Log4s support for Log4Cats.
log4cats-mtl Provide MTL support for Log4Cats.
log4cats-scribe Scribe support for Log4Cats.
Log4Cats Functional logging.
mapref Refs optimized around maps.
mau A tiny library for an auto polling ref.
monadic-html Tiny DOM binding library for Scala.js.
mongo4cats MongoDB Scala client wrapper for Cats Effect & Fs2.
mongosaur Fs2-based MongoDB driver.
monix bio Io alternative with typed errors.
monix-connect stream integrations for Monix.
monix-kafka Monix integration with Kafka.
monix-nio Java NIO utilities for usage with Monix.
monix High-performance library for composing asynchronous and event-based programs.
monocle An optics library for Scala (and Scala.js) strongly inspired by Haskell Lens.
monoids Generic Monoids in Scala.
morphling Free applicative schemas & instance derivation.
mules-http4s-redis Mules Distributed Http Caching Support.
mules-http4s Mules Http4s Caching Implementation for Caching Servers and Client Http Interactions According to the Http Spec.
mules-redis Mules Redis Support.
mysql-binlog-stream Stream MySQL binlog events with Fs2.
natchez An opentracing library, to use with Jaegger, Honeycomb, OpenCensus, and Lightstep.
neotypes A Scala lightweight, type-safe & asynchronous driver for neo4j. Support streaming queries using Fs2.
neutron Apache Pulsar bindings for Fs2.
newts Defines newtypes compatible with Cats type classes.
odin Fast & functional logger with own logging backend.
origami Monadic folds.
phony Fake data generator.
pulsar4s concise, idiomatic, reactive, type safe Scala client for Apache Pulsar.
pureconfig A boilerplate-free library for loading configuration files.
rainier Bayesian inference in Scala.
random Pure randomness in Scala.
read Read Typeclass.
redis4cats Redis client built on top of Fs2 and Cats Effect.
refined Simple refinement types for Scala.
sangria-monix Sangria integration for Monix.
sbt-mima-version-check Plugin to automate which mima versions to check.
scala cache A facade for the most popular cache implementations for Scala.
scala-forex Exchange rate lookups.
scala-maxmind-ip-lookups IP geolocation through the Maxmind database.
scala-referer-parser Referer parsing.
scala-rl Functional, monadic reinforcement learning in Scala.
scala-weather Weather lookups.
scanamo Simpler DynamoDB access for Scala.
scarctic Fs2-based driver for MAN/AHL’s Arctic data store.
scodec-protocols A library for working with libpcap files. Contains many interesting pipes (e.g., working with time series and playing back streams at various rates).
scodec-stream A library for streaming binary decoding and encoding, built using Fs2 and scodec.
seals Tools for schema evolution and language-integrated schemata.
semigroups Set of generic semigroup types and accompanying instances very useful for abstract programming.
shims Seamless interoperability for Cats and Scalaz typeclasses and datatypes.
skunk A data access library for Scala + Postgres.
snowflake4s Functional snowflake id generator.
spata CSV parser build on Fs2.
spinoco/fs2-kafka Simple client for Apache Kafka.
sqs4s A pure Scala client for AWS SQS using Fs2.
streamz A library that supports the conversion of Akka Stream Sources, Flows and Sinks to and from Fs2 Streams, Pipes and Sinks, respectively. It also supports the usage of Apache Camel endpoints in Fs2 Streams and Akka Stream Sources, Flows and SubFlows.
sttp The Scala HTTP client you always wanted.
sup Composable, purely functional healthchecks in Scala.
synchronized Synchronous resource access.
system-effect Console and Environment Simple Tools.
testcontainers-specs2 Test Containers Support for Specs2.
tsec Typesafe, functional, general purpose cryptography and security library.
unique Unique functional values for Scala.
upperbound A purely functional, interval-based rate limiter with support for backpressure.
vault Type-safe, persistent storage for values of arbitrary types.
vinyldns A DNS governance system using Fs2 for throttling updates to DNS backends.
whale-tail Docker Daemon Integration.

Your project talks Cats too? Submit a PR to add it here!

The full-size Cats logo is available for use for Cats related projects, contents, souvenirs, etc.

We offer a Cats Friendly Badge to let others know your project works with Cats!

Below are quick html and markdown snippets to use the badge in your own project.

html
<a href=""><img src="https://typelevel.org/cats/img/cats-badge-tiny.png" alt="Cats friendly" /></a>
markdown

Datatypes Chain (`docs/datatypes/chain.md`)

Chain

API Documentation: @:api(cats.data.Chain)

Chain is an immutable sequence data structure that allows constant time prepending, appending and concatenation.
This makes it especially efficient when used as a [Monoid], e.g. with [Validated] or [Writer].
As such it aims to be used where @:api(scala.collection.immutable.List) and @:api(scala.collection.immutable.Vector) incur a performance penalty.
Cats also includes type class implementations to support using Chain as a general-purpose collection type, including [Traverse], [Monad], and [Alternative].

Motivation

List is a great data type, it is very simple and easy to understand.
It has very low overhead for the most important functions such as [fold][Foldable] and [map][Functor] and also supports prepending a single element in constant time.

Traversing a data structure with something like [Writer[List[Log], A]][Writer] or [ValidatedNel[Error, A]][Validated] is powerful and allows us to precisely specify what kind of iteration we want to do while remaining succinct.
However, in terms of efficiency it's a whole different story unfortunately.
That is because both of these traversals make use of the List monoid (or the [NonEmptyList] semigroup), which by the nature of List is very inefficient.
If you use [traverse][Traverse] with a data structure with n elements and [Writer] or [Validated] as the [Applicative] type, you will end up with a runtime of O(n^2).
This is because, with List, appending a single element requires iterating over the entire data structure and therefore takes linear time.

So @:api(scala.collection.immutable.List) isn't all that great for this use case, so let's use @:api(scala.collection.immutable.Vector) or @:api(cats.data.NonEmptyVector)` instead, right?

Well, Vector has its own problems and in this case it's unfortunately not that much faster than List at all. You can check this blog post by Li Haoyi for some deeper insight into Vector's issues.

Chain evolved from what used to be fs2.Catenable and Erik Osheim's Chain library.
Similar to List, it is also a very simple data structure, but unlike List it supports constant O(1) time append, prepend and concat.
This makes its [Monoid] instance [super performant][Benchmarks] and a much better fit for usage with [Validated], [Writer], [Ior] or [Const].

NonEmptyChain

NonEmptyChain is the non-empty version of Chain.
It does not have a [Monoid] instance since it cannot be empty, but it does have a [Semigroup] instance.
Likewise, it defines a [NonEmptyTraverse] instance, but no @:api(cats.TraverseFilter) instance.

To simplify the usage of NonEmptyChain, Cats includes type aliases like ValidatedNec and IorNec, as well as helper functions like groupByNec and Validated.invalidNec.

There are numerous ways to construct a NonEmptyChain, e.g. you can create one from a single element, a NonEmptyList or a NonEmptyVector:

scala mdoc
import cats.data._

NonEmptyChain(1, 2, 3, 4)

NonEmptyChain.fromNonEmptyList(NonEmptyList(1, List(2, 3)))
NonEmptyChain.fromNonEmptyVector(NonEmptyVector(1, Vector(2, 3)))

NonEmptyChain.one(1)

You can also create an @:api(scala.Option) of NonEmptyChain from a Chain or any other collection type:

scala mdoc
import cats.data._

NonEmptyChain.fromChain(Chain(1, 2, 3))
NonEmptyChain.fromSeq(List.empty[Int])
NonEmptyChain.fromSeq(Vector(1, 2, 3))

Sometimes, you'll want to prepend or append a single element to a chain and return the result as a NonEmptyChain:

scala mdoc
import cats.data._

NonEmptyChain.fromChainAppend(Chain(1, 2, 3), 4)
NonEmptyChain.fromChainAppend(Chain.empty[Int], 1)
NonEmptyChain.fromChainPrepend(1, Chain(2, 3))

How it works

Chain is implemented as a simple unbalanced binary tree ADT with four cases:
an empty Chain with no elements, a singleton Chain with exactly one element, a concatenation of two chains, or a wrapper for a @:api(scala.collection.immutable.Seq).

In code it looks like this:

scala mdoc
sealed abstract class Chain[+A]

case object Empty extends Chain[Nothing]
case class Singleton[A](a: A) extends Chain[A]
case class Append[A](left: Chain[A], right: Chain[A]) extends Chain[A]
case class Wrap[A](seq: Seq[A]) extends Chain[A]

The Append constructor is what gives us the fast concatenation ability.
Concatenating two existing Chains is just a call to the Append constructor, which is always constant time O(1).

In case we want to append or prepend a single element,
all we have to do is wrap the element with the Singleton constructor and then use the Append constructor to append or prepend the Singleton Chain.

The Wrap constructor lifts any Seq into a Chain.
This can be useful for concatenating already created collections that don't have great concatenation performance.
Append(Wrap(list1), Wrap(list2)).foldMap(f) will in general be much faster than just concatenating list1 and list2 and folding the result.

Chain doesn't directly expose the Append and Wrap constructors, because the arguments might refer to an empty Chain or Seq.
Instead of calling Append directly you can simply use Chain.concat or ++, which will check if one of the arguments is empty:

scala
def concat[A](c: Chain[A], c2: Chain[A]): Chain[A] =
  if (c.isEmpty) c2
  else if (c2.isEmpty) c
  else Append(c, c2)

To construct a Chain from a Seq you should use Chain.fromSeq which will also check for emptiness:

scala
def fromSeq[A](s: Seq[A]): Chain[A] =
  if (s.isEmpty) nil
  else if (s.lengthCompare(1) == 0) one(s.head)
  else Wrap(s)

In conclusion Chain supports constant time concatenation, because it builds an unbalance tree of Appends.
append and prepend are treated as concatenation with single element collection to keep the same performance characteristics.
This unbalanced tree will always allow iteration in linear time.

Benchmarks

To get a good idea of performance of Chain, here are some benchmarks that test monoidal append (higher score is better):

text
Benchmark                                Mode  Cnt         Score         Error  Units
CollectionMonoidBench.accumulateChain   thrpt   25        81.973 ±       3.921  ops/s
CollectionMonoidBench.accumulateList    thrpt   25        21.150 ±       1.756  ops/s
CollectionMonoidBench.accumulateVector  thrpt   25        11.725 ±       0.306  ops/s

As you can see accumulating things with Chain is almost 4 times faster than List and nearly 8 times faster than Vector.
So appending is a lot more performant than the standard library collections, but what about operations like map or fold?
Fortunately we've also benchmarked these (again, higher score is better):

text
/* Detailed source-code truncated for AI context efficiency. */

While not dominant, Chain performance is in the middle of the pack for most operations benchmarked.
Chain does have poor random access performance, and should be avoided in favor of Vector for random access heavy use cases.

Chain excels with concatenation heavy workloads and has comparable performance to List and Vector for most other operations.
So next time you write any code that uses List or Vector as a [Monoid], be sure to use Chain instead!

Note: All benchmarks above were run using JMH 1.32 with Scala 2.13.8 on JDK 11.
For full details, see here.
You can also check out the benchmark source code.


Datatypes Const (`docs/datatypes/const.md`)

Const

API Documentation: @:api(cats.data.Const)

At first glance Const seems like a strange data type - it has two type parameters, yet only
stores a value of the first type. What possible use is it? As it turns out, it does
have its uses, which serve as a nice example of the consistency and elegance of functional programming.

Thinking about `Const`

The Const data type can be thought of similarly to the const function, but as a data type.

scala mdoc:silent
def const[A, B](a: A)(b: => B): A = a

The const function takes two arguments and simply returns the first argument, ignoring the second.

scala mdoc:silent
case class Const[A, B](getConst: A)

The Const data type takes two type parameters, but only ever stores a value of the first type parameter.
Because the second type parameter is not used in the data type, the type parameter is referred to as a
"phantom type".

Why do we care?

It would seem Const gives us no benefit over a data type that would simply not have the second type parameter.
However, while we don't directly use the second type parameter, its existence becomes useful in certain contexts.

Example 1: Lens

The following is heavily inspired by Julien Truffaut's
blog post on
Monocle, a fully-fledged optics library in Scala.

Types that contain other types are common across many programming paradigms. It is of course desirable in many
cases to get out members of other types, or to set them. In traditional object-oriented programming this is
handled by getter and setter methods on the outer object. In functional programming, a popular solution is
to use a lens.

A lens can be thought of as a first class getter/setter. A Lens[S, A] is a data type that knows how to get
an A out of an S, or set an A in an S.

scala mdoc:silent
trait Lens[S, A] {
  def get(s: S): A

  def set(s: S, a: A): S

  def modify(s: S)(f: A => A): S =
    set(s, f(get(s)))
}

It can be useful to have effectful modifications as well - perhaps our modification can fail (Option) or
can return several values (List).

scala mdoc:nest:silent
trait Lens[S, A] {
  def get(s: S): A

  def set(s: S, a: A): S

  def modify(s: S)(f: A => A): S =
    set(s, f(get(s)))

  def modifyOption(s: S)(f: A => Option[A]): Option[S] =
    f(get(s)).map(a => set(s, a))

  def modifyList(s: S)(f: A => List[A]): List[S] =
    f(get(s)).map(a => set(s, a))
}

Note that both modifyOption and modifyList share the exact same implementation. If we look closely, the
only thing we need is a map operation on the data type. Being good functional programmers, we abstract.

scala mdoc:nest:silent
import cats.Functor
import cats.syntax.all._

trait Lens[S, A] {
  def get(s: S): A

  def set(s: S, a: A): S

  def modify(s: S)(f: A => A): S =
    set(s, f(get(s)))

  def modifyF[F[_] : Functor](s: S)(f: A => F[A]): F[S] =
    f(get(s)).map(a => set(s, a))
}

We can redefine modify in terms of modifyF by using cats.Id. We can also treat set as a modification
that simply ignores the current value. Due to these modifications however, we must leave modifyF abstract
since having it defined in terms of set would lead to infinite circular calls.

scala mdoc:nest:silent
import cats.Id

trait Lens[S, A] {
  def modifyF[F[_] : Functor](s: S)(f: A => F[A]): F[S]

  def set(s: S, a: A): S = modify(s)(_ => a)

  def modify(s: S)(f: A => A): S = modifyF[Id](s)(f)

  def get(s: S): A
}

What about get? Certainly we can't define get in terms of the others.. the others are to modify an existing
value, whereas get is to retrieve it. Let's give it a shot anyways.

Looking at modifyF, we have an S we can pass in. The tricky part will be the A => F[A], and then somehow
getting an A out of F[S]. If we imagine F to be a type-level constant function however, we could imagine
it would simply take any type and return some other constant type, an A perhaps. This suggests our F is a
Const.

We then take a look at the fact that modifyF takes an F[_], a type constructor that takes a single type parameter.
Const takes two, so we must fix one. The function returns an F[S], but we want an A, which implies we
have the first type parameter fixed to A and leave the second one free for the function to fill in as it wants.

Substituting in Const[A, _] wherever we see F[_], the function wants an A => Const[A, A] and will give us back
a Const[A, S]. Looking at the definition of Const, we see that we only ever have a value of the first type parameter
and completely ignore the second. Therefore, we can treat any Const[X, Y] value as equivalent to X (plus or minus
some wrapping into Const). This leaves us with needing a function A => A. Given the type, the only thing we can do
is to take an A and return it right back (lifted into Const).

Before we plug and play however, note that modifyF has a Functor constraint on F[_]. This means we need to
define a Functor instance for Const, where the first type parameter is fixed.

Note: the example below assumes usage of the kind-projector compiler plugin and will not compile if it is not being used in a project.

scala mdoc:reset:silent
import cats.Functor
import cats.data.Const

implicit def constFunctor[X]: Functor[Const[X, *]] =
  new Functor[Const[X, *]] {
    // Recall Const[X, A] ~= X, so the function is not of any use to us
    def map[A, B](fa: Const[X, A])(f: A => B): Const[X, B] =
      Const(fa.getConst)
  }

Now that that's taken care of, let's substitute and see what happens.

scala mdoc:silent
import cats.Id

trait Lens[S, A] {
  def modifyF[F[_] : Functor](s: S)(f: A => F[A]): F[S]

  def set(s: S, a: A): S = modify(s)(_ => a)

  def modify(s: S)(f: A => A): S = modifyF[Id](s)(f)

  def get(s: S): A = {
    val storedValue = modifyF[Const[A, *]](s)(a => Const(a))
    storedValue.getConst
  }
}

It works! We get a Const[A, S] out on the other side, and we simply just retrieve the A value stored inside.

What's going on here? We can treat the effectful "modification" we are doing as a store operation - we take an A
and store it inside a Const. Knowing only F[_] has a Functor instance, it can only map over the Const
which will do nothing to the stored value. After modifyF is done getting the new S, we retrieve the stored A
value and we're done!

Example 2: Traverse

In the popular The Essence of the Iterator Pattern
paper, Jeremy Gibbons and Bruno C. d. S. Oliveria describe a functional approach to iterating over a collection of
data. Among the abstractions presented are Foldable and Traverse, replicated below (also available in Cats).

scala mdoc:silent
import cats.{Applicative, Monoid}

trait Foldable[F[_]] {
  // Given a collection of data F[A], and a function mapping each A to a B where B has a Monoid instance,
  // reduce the collection down to a single B value using the monoidal behavior of B
  def foldMap[A, B : Monoid](fa: F[A])(f: A => B): B
}

trait Traverse[F[_]] {
  // Given a collection of data F[A], for each value apply the function f which returns an effectful
  // value. The result of traverse is the composition of all these effectful values.
  def traverse[G[_] : Applicative, A, B](fa: F[A])(f: A => G[B]): G[F[B]]
}

These two type classes seem unrelated - one reduces a collection down to a single value, the other traverses
a collection with an effectful function, collecting results. It may be surprising to see that in fact Traverse
subsumes Foldable.

scala mdoc:nest:silent
trait Traverse[F[_]] extends Foldable[F] {
  def traverse[G[_] : Applicative, A, X](fa: F[A])(f: A => G[X]): G[F[X]]

  def foldMap[A, B : Monoid](fa: F[A])(f: A => B): B
}

To start, we observe that if we are to implement foldMap in terms of traverse, we will want a B out
at some point. However, traverse returns a G[F[X]]. It would seem there is no way to unify these two.
However, if we imagine G[_] to be a sort of type-level constant function, where the fact that it's taking a
F[X] is irrelevant to the true underlying value, we can begin to see how we might be able to pull this off.

traverse however wants G[_] to have an Applicative instance, so let's define one for Const. Since
F[X] is the value we want to ignore, we treat it as the second type parameter and hence, leave it as the free
one.

scala mdoc:nest:silent
import cats.data.Const

implicit def constApplicative[Z]: Applicative[Const[Z, *]] =
  new Applicative[Const[Z, *]] {
    def pure[A](a: A): Const[Z, A] = ???

    def ap[A, B](f: Const[Z, A => B])(fa: Const[Z, A]): Const[Z, B] = ???
  }

Recall that Const[Z, A] means we have a Z value in hand, and don't really care about the A type parameter.
Therefore we can more or less treat the type Const[Z, A] as just Z.

In functions pure and ap we have a problem. In pure, we have an A value, but want to return a Z value. We have
no function A => Z, so our only option is to completely ignore the A value. But we still don't have a Z! Let's
put that aside for now, but still keep it in the back of our minds.

In ap we have two Z values, and want to return a Z value. We could certainly return one or the other, but we
should try to do something more useful. This suggests composition of Zs, which we don't know how to do.

So now we need a constant Z value, and a binary function that takes two Zs and produces a Z. Sound familiar?
We want Z to have a Monoid instance!

scala mdoc:nest:silent
implicit def constApplicative[Z : Monoid]: Applicative[Const[Z, *]] =
  new Applicative[Const[Z, *]] {
    def pure[A](a: A): Const[Z, A] = Const(Monoid[Z].empty)

    def ap[A, B](f: Const[Z, A => B])(fa: Const[Z, A]): Const[Z, B] =
      Const(Monoid[Z].combine(fa.getConst, f.getConst))
  }

We have our Applicative!

Going back to Traverse, we fill in the first parameter of traverse with fa since that's
the only value that fits.

Now we need a A => G[B]. We have an A => B, and we've decided to use Const for our G[_]. We need to
fix the first parameter of Const since Const takes two type parameters and traverse wants a type constructor
which only takes one. The first type parameter which will be the type of the actual values we store, and therefore will
be the type of the value we get out at the end, so we leave the second one free, similar to the Applicative instance.
We don't care about the second type parameter and there are no restrictions on it, so we can just use Nothing,
the type that has no values.

So to summarize, what we want is a function A => Const[B, Nothing], and we have a function A => B. Recall
that Const[B, Z] (for any Z) is the moral equivalent of just B, so A => Const[B, Nothing] is equivalent
to A => B, which is exactly what we have, we just need to wrap it.

scala mdoc:nest:silent
trait Traverse[F[_]] extends Foldable[F] {
  def traverse[G[_] : Applicative, A, X](fa: F[A])(f: A => G[X]): G[F[X]]

  def foldMap[A, B : Monoid](fa: F[A])(f: A => B): B = {
    val const: Const[B, F[Nothing]] = traverse[Const[B, *], A, Nothing](fa)(a => Const(f(a)))
    const.getConst
  }
}

Hurrah!

What's happening here? We can see traverse is a function that goes over a collection, applying an
effectful function to each value, and combining all of these effectful values. In our case, the effect
is mapping each value to a value of type B, where we know how to combine Bs via its Monoid instance.
The Monoid instance is exactly what is used when traverse goes to collect the effectful values together.
Should the F[A] be "empty", it can use Monoid#empty as a value to return back.

Pretty nifty. traverse-ing over a collection with an effectful function is more general than traversing
over a collection to reduce it down to a single value.


Datatypes Contt (`docs/datatypes/contt.md`)

ContT

API Documentation: @:api(cats.data.ContT)

A pattern that appears sometimes in functional programming is that of a function
first computing some kind of intermediate result and then passing that result to
another function which was passed in as an argument, in order to delegate the
computation of the final result.

For example:

scala mdoc:silent
case class User(id: Int, name: String, age: Int)
sealed abstract class UserUpdateResult
case class Succeeded(updatedUserId: Int) extends UserUpdateResult
case object Failed extends UserUpdateResult
scala mdoc
import cats.Eval

def updateUser(persistToDatabase: User => Eval[UserUpdateResult])
              (existingUser: User, newName: String, newAge: Int): Eval[UserUpdateResult] = {
  val trimmedName = newName.trim
  val cappedAge = newAge max 150
  val updatedUser = existingUser.copy(name = trimmedName, age = cappedAge)

  persistToDatabase(updatedUser)
}

(Note: We will be using Eval throughout the examples on this page. If you are not
familiar with Eval, it's worth reading the Eval documentation first.)

Our updateUser function takes in an existing user and some updates to perform.
It sanitises the inputs and updates the user model, but it delegates the
database update to another function which is passed in as an argument.

This pattern is known as "continuation passing style" or CPS, and the function
passed in (persistToDatabase) is known as a "continuation".

Note the following characteristics:

  • The return type of our updateUser function (Eval[UserUpdateResult]) is the
    same as the return type of the continuation function that was passed in.
  • Our function does a bit of work to build an intermediate value, then passes
    that value to the continuation, which takes care of the remainder of the
    work.

In Cats we can encode this pattern using the ContT data type:

scala mdoc
import cats.data.ContT

def updateUserCont(existingUser: User,
                   newName: String,
                   newAge: Int): ContT[Eval, UserUpdateResult, User] =
  ContT.apply[Eval, UserUpdateResult, User] { next =>
    val trimmedName = newName.trim
    val cappedAge = newAge min 150
    val updatedUser = existingUser.copy(name = trimmedName, age = cappedAge)

    next(updatedUser)
  }

We can construct a computation as follows:

scala mdoc
val existingUser = User(100, "Alice", 42)

val computation = updateUserCont(existingUser, "Bob", 200)

And then call run on it, passing in a function of type User => Eval[UserUpdateResult] as the continuation:

scala mdoc
val eval = computation.run { user =>
  Eval.later {
    println(s"Persisting updated user to the DB: $user")
    Succeeded(user.id)
  }
}

Finally we can run the resulting Eval to actually execute the computation:

scala mdoc
eval.value

Composition

You might be wondering what the point of all this was, as the function that uses
ContT seems to achieve the same thing as the original function, just encoded
in a slightly different way.

The point is that ContT is a monad, so by rewriting our function into a
ContT we gain composibility for free.

For example we can map over a ContT:

scala mdoc
val anotherComputation = computation.map { user =>
  Map(
    "id" -> user.id.toString,
    "name" -> user.name,
    "age" -> user.age.toString
  )
}

val anotherEval = anotherComputation.run { userFields =>
  Eval.later {
    println(s"Persisting these fields to the DB: $userFields")
    Succeeded(userFields("id").toInt)
  }
}

anotherEval.value

And we can use flatMap to chain multiple ContTs together.

The following example builds 3 computations: one to sanitise the inputs and
update the user model, one to persist the updated user to the database, and one
to publish a message saying the user was updated. It then chains them together
in continuation-passing style using flatMap and runs the whole computation.

scala mdoc:nest
val updateUserModel: ContT[Eval, UserUpdateResult, User] =
  updateUserCont(existingUser, "Bob", 200).map { updatedUser =>
    println("Updated user model")
    updatedUser
  }

val persistToDb: User => ContT[Eval, UserUpdateResult, UserUpdateResult] = {
  user =>
    ContT.apply[Eval, UserUpdateResult, UserUpdateResult] { next =>
      println(s"Persisting updated user to the DB: $user")

      next(Succeeded(user.id))
    }
}

val publishEvent: UserUpdateResult => ContT[Eval, UserUpdateResult, UserUpdateResult] = {
  userUpdateResult =>
    ContT.apply[Eval, UserUpdateResult, UserUpdateResult] { next =>
      userUpdateResult match {
        case Succeeded(userId) =>
          println(s"Publishing 'user updated' event for user ID $userId")
        case Failed =>
          println("Not publishing 'user updated' event because update failed")
      }

      next(userUpdateResult)
    }
}

val chainOfContinuations =
  updateUserModel flatMap persistToDb flatMap publishEvent

val eval = chainOfContinuations.run { finalResult =>
  Eval.later {
    println("Finished!")
    finalResult
  }
}

eval.value

Why Eval?

If you're wondering why we used Eval in our examples above, it's because the
Monad instance for ContT[M[_], A, B] requires an instance of cats.Defer
for M[_]. This is an implementation detail - it's needed in order to preserve
stack safety.

In a real-world application, you're more likely to be using something like
cats-effect IO, which has a Defer instance.


Datatypes Either (`docs/datatypes/either.md`)

{% laika.excludeFromNavigation = true %}

Either

The Either type is provided by the Scala standard library, but Cats provides syntax enrichment and typeclass instances
to extend its functionality, including [Functor], [Applicative], [Monad] and
MonadError.

If you would like to accumulate errors instead of the short-circuiting behavior of Either, see the
[Parallel] typeclass, or the [Validated] data type.


Datatypes Eithert (`docs/datatypes/eithert.md`)

EitherT

API Documentation: @:api(cats.data.EitherT)

Either can be used for error handling in most situations. However, when
Either is placed into effectful types such as Option orFuture, a large
amount of boilerplate is required to handle errors. For example, consider the
following program:

scala mdoc
import scala.util.Try
import cats.syntax.all._

def parseDouble(s: String): Either[String, Double] =
  Try(s.toDouble).map(Right(_)).getOrElse(Left(s"$s is not a number"))

def divide(a: Double, b: Double): Either[String, Double] =
  Either.cond(b != 0, a / b, "Cannot divide by zero")

def divisionProgram(inputA: String, inputB: String): Either[String, Double] =
  for {
    a <- parseDouble(inputA)
    b <- parseDouble(inputB)
    result <- divide(a, b)
  } yield result

divisionProgram("4", "2") // Right(2.0)
divisionProgram("a", "b") // Left("a is not a number")

Suppose parseDouble and divide are rewritten to be asynchronous and return
Future[Either[String, Double]] instead. The for-comprehension can no longer be
used since divisionProgram must now compose Future and Either together,
which means that the error handling must be performed explicitly to ensure that
the proper types are returned:

scala mdoc:silent
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

def parseDoubleAsync(s: String): Future[Either[String, Double]] =
  Future.successful(parseDouble(s))
def divideAsync(a: Double, b: Double): Future[Either[String, Double]] =
  Future.successful(divide(a, b))

def divisionProgramAsync(inputA: String, inputB: String): Future[Either[String, Double]] =
  parseDoubleAsync(inputA) flatMap { eitherA =>
    parseDoubleAsync(inputB) flatMap { eitherB =>
      (eitherA, eitherB) match {
        case (Right(a), Right(b)) => divideAsync(a, b)
        case (Left(err), _) => Future.successful(Left(err))
        case (_, Left(err)) => Future.successful(Left(err))
      }
    }
  }

Clearly, the updated code is less readable and more verbose: the details of the
program are now mixed with the error handling. In addition, as more Eithers
and Futures are included, the amount of boilerplate required to properly
handle the errors will increase dramatically.

EitherT

EitherT[F[_], A, B] is a lightweight wrapper for F[Either[A, B]] that makes
it easy to compose Eithers and Fs together. To use EitherT, values of
Either, F, A, and B are first converted into EitherT, and the
resulting EitherT values are then composed using combinators. For example, the
asynchronous division program can be rewritten as follows:

scala mdoc:nest
import cats.data.EitherT
import cats.syntax.all._

def divisionProgramAsync(inputA: String, inputB: String): EitherT[Future, String, Double] =
  for {
    a <- EitherT(parseDoubleAsync(inputA))
    b <- EitherT(parseDoubleAsync(inputB))
    result <- EitherT(divideAsync(a, b))
  } yield result

divisionProgramAsync("4", "2").value
divisionProgramAsync("a", "b").value

Note that when F is a monad, then EitherT will also form a monad, allowing
monadic combinators such as flatMap to be used in composing EitherT values.

From `A` or `B` to `EitherT[F, A, B]`

To obtain a left version or a right version of EitherT when given an A or a
B, use EitherT.leftT and EitherT.rightT (which is an alias for
EitherT.pure), respectively.

scala mdoc:silent
val number: EitherT[Option, String, Int] = EitherT.rightT(5)
val error: EitherT[Option, String, Int] = EitherT.leftT("Not a number")

From `F[A]` or `F[B]` to `EitherT[F, A, B]`

Similarly, use EitherT.left and EitherT.right to convert an F[A] or an F[B]
into an EitherT. It is also possible to use EitherT.liftF as an alias for
EitherT.right.

scala mdoc:nest:silent
val numberO: Option[Int] = Some(5)
val errorO: Option[String] = Some("Not a number")

val number: EitherT[Option, String, Int] = EitherT.right(numberO)
val error: EitherT[Option, String, Int] = EitherT.left(errorO)

From `Either[A, B]` or `F[Either[A, B]]` to `EitherT[F, A, B]`

Use EitherT.fromEither to lift a value of Either[A, B] into EitherT[F, A, B].
An F[Either[A, B]] can be converted into EitherT using the EitherT constructor.

scala mdoc:silent
val numberE: Either[String, Int] = Right(100)
val errorE: Either[String, Int] = Left("Not a number")
val numberFE: List[Either[String, Int]] = List(Right(250))

val numberET: EitherT[List, String, Int] = EitherT.fromEither(numberE)
val errorET: EitherT[List, String, Int] = EitherT.fromEither(errorE)
val numberFET: EitherT[List, String, Int] = EitherT(numberFE)

From `Option[B]` or `F[Option[B]]` to `EitherT[F, A, B]`

An Option[B] or an F[Option[B]], along with a default value, can be passed to
EitherT.fromOption and EitherT.fromOptionF, respectively, to produce an
EitherT. For F[Option[B]] and default F[A], there is EitherT.fromOptionM.

scala mdoc
val myOption: Option[Int] = None
val myOptionList: List[Option[Int]] = List(None, Some(2), Some(3), None, Some(5))

val myOptionET = EitherT.fromOption[Future](myOption, "option not defined")
val myOptionListET = EitherT.fromOptionF(myOptionList, "option not defined")
val myOptionListETM = EitherT.fromOptionM(myOptionList, List("option not defined"))

From `ApplicativeError[F, E]` to `EitherT[F, E, A]`

An ApplicativeError[F, E] or a MonadError[F, E], can be converted into EitherT[F, E, A]
using the attemptT method on them.

scala mdoc:silent
val myTry: Try[Int] = Try(2)
val myFuture: Future[String] = Future.failed(new Exception())

val myTryET: EitherT[Try, Throwable, Int] = myTry.attemptT
val myFutureET: EitherT[Future, Throwable, String] = myFuture.attemptT

Extracting an `F[Either[A, B]]` from an `EitherT[F, A, B]`

Use the value method defined on EitherT to retrieve the underlying F[Either[A, B]]:

scala mdoc:nest
val errorT: EitherT[Future, String, Int] = EitherT.leftT("foo")

val error: Future[Either[String, Int]] = errorT.value

Datatypes Eval (`docs/datatypes/eval.md`)

Eval

API Documentation: @:api(cats.Eval)

Eval is a data type for controlling synchronous evaluation.
Its implementation is designed to provide stack-safety at all times using a technique called trampolining.

There are two different factors that play into evaluation: memoization and laziness.

Memoized evaluation evaluates an expression only once and then remembers (memoizes) that value.
Lazy evaluation refers to when the expression is evaluated.
We talk about eager evaluation if the expression is immediately evaluated when defined and about lazy evaluation if the expression is evaluated when it's first used.

For example, in Scala, a lazy val is both lazy and memoized, a method definition def is lazy, but not memoized, since the body will be evaluated on every call.
A normal val evaluates eagerly and also memoizes the result.

Eval is able to express all of these evaluation strategies and allows us to chain computations using its Monad instance.

Eval.now

First of the strategies is eager evaluation, we can construct an Eval eagerly using Eval.now:

scala mdoc
import cats.Eval
import cats.syntax.all._


val eager = Eval.now {
  println("Running expensive calculation...")
  1 + 2 * 3
}

We can run the computation using the given evaluation strategy anytime by using the value method.

scala mdoc
eager.value

Eval.later

If we want lazy evaluation, we can use Eval.later:

scala mdoc
val lazyEval = Eval.later {
  println("Running expensive calculation...")
  1 + 2 * 3
}

lazyEval.value

lazyEval.value

Notice that "Running expensive calculation" is printed only once, since the value was memoized internally.
Eval.later is different to using a lazy val in a few different ways.
First, it allows the runtime to perform garbage collection of the thunk after evaluation, leading to more memory being freed earlier.
Secondly, when lazy vals are evaluated, in order to preserve thread-safety, the Scala compiler will lock the whole surrounding class, whereas Eval will only lock itself.

Eval.always

If we want lazy evaluation, but without memoization akin to Function0, we can use Eval.always

scala mdoc
val always = Eval.always {
  println("Running expensive calculation...")
  1 + 2 * 3
}

always.value

always.value

Here we can see, that the expression is evaluated every time we call .value.

Chaining lazy computations

One of the most useful applications of Eval is its ability to chain together computations in a stack-safe way.
You can see one such usage when looking at the foldRight method found in Foldable.
Another great example are mutual tail-recursive calls:

scala mdoc
object MutualRecursion {
  def even(n: Int): Eval[Boolean] =
    Eval.always(n == 0).flatMap {
      case true => Eval.True
      case false => odd(n - 1)
    }

  def odd(n: Int): Eval[Boolean] =
    Eval.always(n == 0).flatMap {
      case true => Eval.False
      case false => even(n - 1)
    }
}


MutualRecursion.odd(199999).value

Because Eval guarantees stack-safety, we can chain a lot of computations together using flatMap without fear of blowing up the stack.

You can also use Eval.defer to defer any computation that will return an Eval[A].
This is useful, because nesting a call to .value inside any of the Eval creation methods can be unsafe.


Datatypes Freeapplicative (`docs/datatypes/freeapplicative.md`)

Free Applicative

API Documentation: @:api(cats.free.FreeApplicative)

FreeApplicatives are similar to Free (monads) in that they provide a nice way to represent
computations as data and are useful for building embedded DSLs (EDSLs). However, they differ
from Free in that the kinds of operations they support are limited, much like the distinction
between Applicative and Monad.

Dependency

If you'd like to use cats' free applicative, you'll need to add a library dependency
for the cats-free module.

Example

Consider building an EDSL for validating strings - to keep things simple we'll just have
a way to check a string is at least a certain size and to ensure the string contains numbers.

scala mdoc:silent
sealed abstract class ValidationOp[A]
case class Size(size: Int) extends ValidationOp[Boolean]
case object HasNumber extends ValidationOp[Boolean]

Much like the Free monad tutorial, we use smart constructors to lift our algebra into the FreeApplicative.

scala mdoc:silent
import cats.free.FreeApplicative
import cats.free.FreeApplicative.lift

type Validation[A] = FreeApplicative[ValidationOp, A]

def size(size: Int): Validation[Boolean] = lift(Size(size))

val hasNumber: Validation[Boolean] = lift(HasNumber)

Because a FreeApplicative only supports the operations of Applicative, we do not get the nicety
of a for-comprehension. We can however still use Applicative syntax provided by Cats.

scala mdoc:silent
import cats.syntax.all._

val prog: Validation[Boolean] = (size(5), hasNumber).mapN { case (l, r) => l && r}

As it stands, our program is just an instance of a data structure - nothing has happened
at this point. To make our program useful we need to interpret it.

scala mdoc:silent
import cats.Id
import cats.arrow.FunctionK
import cats.syntax.all._

// a function that takes a string as input
type FromString[A] = String => A

val compiler = new FunctionK[ValidationOp, FromString] {
  def apply[A](fa: ValidationOp[A]): FromString[A] = str =>
    fa match {
      case Size(size) => str.size >= size
      case HasNumber  => str.exists(c => "0123456789".contains(c))
    }
}
scala mdoc
val validator = prog.foldMap[FromString](compiler)
validator("1234")
validator("12345")

Differences from `Free`

So far everything we've been doing has been not much different from Free - we've built
an algebra and interpreted it. However, there are some things FreeApplicative can do that
Free cannot.

Recall a key distinction between the type classes Applicative and Monad - Applicative
captures the idea of independent computations, whereas Monad captures that of dependent
computations. Put differently Applicatives cannot branch based on the value of an existing/prior
computation. Therefore when using Applicatives, we must hand in all our data in one go.

In the context of FreeApplicatives, we can leverage this static knowledge in our interpreter.

Parallelism

Because we have everything we need up front and know there can be no branching, we can easily
write a validator that validates in parallel.

scala mdoc:silent
import cats.data.Kleisli
import cats.syntax.all._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

// recall Kleisli[Future, String, A] is the same as String => Future[A]
type ParValidator[A] = Kleisli[Future, String, A]

val parCompiler = new FunctionK[ValidationOp, ParValidator] {
  def apply[A](fa: ValidationOp[A]): ParValidator[A] = Kleisli { str =>
    fa match {
      case Size(size) => Future { str.size >= size }
      case HasNumber => Future { str.exists(c => "0123456789".contains(c)) }
    }
  }
}

val parValidator = prog.foldMap[ParValidator](parCompiler)

Logging

We can also write an interpreter that simply creates a list of strings indicating the filters that
have been used - this could be useful for logging purposes. Note that we need not actually evaluate
the rules against a string for this, we simply need to map each rule to some identifier. Therefore
we can completely ignore the return type of the operation and return just a List[String] - the
Const data type is useful for this.

scala mdoc:silent
import cats.data.Const
import cats.syntax.all._

type Log[A] = Const[List[String], A]

val logCompiler = new FunctionK[ValidationOp, Log] {
  def apply[A](fa: ValidationOp[A]): Log[A] = fa match {
    case Size(size) => Const(List(s"size >= $size"))
    case HasNumber => Const(List("has number"))
  }
}

def logValidation[A](validation: Validation[A]): List[String] =
  validation.foldMap[Log](logCompiler).getConst
scala mdoc
logValidation(prog)
logValidation(size(5) *> hasNumber *> size(10))
logValidation((hasNumber, size(3)).mapN(_ || _))

Why not both?

It is perhaps more plausible and useful to have both the actual validation function and the logging
strings. While we could easily compile our program twice, once for each interpreter as we have above,
we could also do it in one go - this would avoid multiple traversals of the same structure.

Another useful property Applicatives have over Monads is that given two Applicatives F[_] and
G[_], their product type FG[A] = (F[A], G[A]) is also an Applicative. This is not true in the general
case for monads.

Therefore, we can write an interpreter that uses the product of the ParValidator and Log Applicatives
to interpret our program in one go. We can create this interpreter easily by using FunctionK#and.

scala mdoc:silent
import cats.data.Tuple2K

type ValidateAndLog[A] = Tuple2K[ParValidator, Log, A]

val prodCompiler: FunctionK[ValidationOp, ValidateAndLog] = parCompiler and logCompiler

val prodValidation = prog.foldMap[ValidateAndLog](prodCompiler)

The way FreeApplicative#foldMap works

Despite being an imperative loop, there is a functional intuition behind FreeApplicative#foldMap.

The new FreeApplicative's foldMap is a sort of mutually-recursive function that operates on an argument stack and a
function stack, where the argument stack has type List[FreeApplicative[F, _]] and the functions have type List[Fn[G, _, _]].
Fn[G[_, _]] contains a function to be Ap'd that has already been translated to the target Applicative,
as well as the number of functions that were Ap'd immediately subsequently to it.

Main re-association loop

Pull an argument out of the stack, eagerly remove right-associated Ap nodes, by looping on the right and
adding the Ap nodes' arguments on the left to the argument stack; at the end, pushes a single function to the
function stack of the applied functions, the rest of which will be pushed in this loop in later iterations.
Once all of the Ap nodes on the right are removed, the loop resets to deal with the ones on the left.

Here's an example FreeApplicative value to demonstrate the loop's function, at the end of every iteration.
Every node in the tree is annotated with an identifying number and the concrete type of the node
(A -> Ap, L -> Lift, P -> Pure), and an apostrophe to denote where argF (the current argument) currently
points; as well the argument and function branches off Ap nodes are explicitly denoted.

text
==> begin.
           '1A
           /  \
       arg/    \fun
         /      \
        /        \
       2A        3A
   arg/  \fun arg/  \fun
     /    \     /    \
    4L    5P   6L     7L

args: Nil
functions: Nil
==> loop.

            1A
           /  \
       arg/    \fun
         /      \
        /        \
       2A        '3A
   arg/  \fun arg/  \fun
     /    \     /    \
    4L    5P   6L    7L

args: 2A :: Nil
functions: Nil
==> loop.

            1A
           /  \
       arg/    \fun
         /      \
        /        \
       2A         3A
   arg/  \fun arg/  \fun
     /    \     /    \
    4L    5P   6L   '7L

args: 6L :: 2A :: Nil
functions: Fn(gab = foldArg(7L), argc = 2) :: Nil
==> finished.

At the end of the loop the entire right branch of Aps under argF has been peeled off into a single curried function,
all of the arguments to that function are on the argument stack and that function itself is on the function stack,
annotated with the amount of arguments it takes.

Function application loop

Once argF isn't an Ap node, a loop runs which pulls functions from the stack until it reaches a curried function,
in which case it applies the function to argF transformed into a G[Any] value, and pushes the resulting function
back to the function stack, before returning to the main loop.

I'll continue the example from before here:

text
==> loop.
            1A
           /  \
       arg/    \fun
         /      \
        /        \
       2A         3A
   arg/  \fun arg/  \fun
     /    \     /    \
    4L    5P  '6L    7L

args: 2A :: Nil
functions: Fn(gab = foldArg(7L) ap foldArg(6L), argc = 1) :: Nil
==> finished.

At the end of this loop every function on the top of the function stack with length == 1 (not curried)
has been applied to a single argument from the argument stack, and the first curried function (length != 1)
on the stack has been applied to a single argument from the argument stack.
The reason we can't keep applying the curried function to arguments is that the node on top of the argument
stack must be an Ap node if the function is curried, so we can't translate it directly to G[_].

Once the last function has been applied to the last argument, the fold has finished and the result is returned.

References

Deeper explanations can be found in this paper Free Applicative Functors by Paolo Capriotti


Datatypes Freemonad (`docs/datatypes/freemonad.md`)

Free Monad

API Documentation: @:api(cats.free.Free)

What is it?

A free monad is a construction which allows you to build a monad
from any Functor. Like other monads, it is a pure way to represent
and manipulate computations.

In particular, free monads provide a practical way to:

  • represent stateful computations as data, and run them
  • run recursive computations in a stack-safe way
  • build an embedded DSL (domain-specific language)
  • retarget a computation to another interpreter using natural transformations

(In Cats, the type representing a free monad is abbreviated as Free[_].)

Using Free Monads

If you'd like to use Cats' free monad, you'll need to add a library dependency
for the cats-free module.

A good way to get a sense for how free monads work is to see them in
action. The next section uses Free[_] to create an embedded DSL
(Domain Specific Language).

If you're interested in the theory behind free monads, the
What is Free in theory? section discusses free monads
in terms of category theory.

Study your topic

Let's imagine that we want to create a DSL for a key-value store. We
want to be able to do three things with keys:

  • put a value into the store, associated with its key.
  • get a value from the store given its key.
  • delete a value from the store given its key.

The idea is to write a sequence of these operations in the embedded
DSL as a "program", compile the "program", and finally execute the
"program" to interact with the actual key-value store.

For example:

scala
put("toto", 3)
get("toto") // returns 3
delete("toto")

But we want:

  • the computation to be represented as a pure, immutable value
  • to separate the creation and execution of the program
  • to be able to support many different methods of execution

Study your grammar

We have 3 commands to interact with our KeyValue store:

  • Put a value associated with a key into the store
  • Get a value associated with a key out of the store
  • Delete a value associated with a key from the store

Create an ADT representing your grammar

ADT stands for Algebraic Data Type. In this context, it refers to a
closed set of types which can be combined to build up complex,
recursive values.

We need to create an ADT to represent our key-value operations:

scala mdoc:silent
sealed trait KVStoreA[A]
case class Put[T](key: String, value: T) extends KVStoreA[Unit]
case class Get[T](key: String) extends KVStoreA[Option[T]]
case class Delete(key: String) extends KVStoreA[Unit]

Free your ADT

There are five basic steps to "freeing" the ADT:

  1. Create a type based on Free[_] and KVStoreA[_].
  2. Create smart constructors for KVStore[_] using liftF.
  3. Build a program out of key-value DSL operations.
  4. Build a compiler for programs of DSL operations.
  5. Execute our compiled program.

1. Create a `Free` type based on your ADT

scala mdoc:silent
import cats.free.Free

type KVStore[A] = Free[KVStoreA, A]

2. Create smart constructors using `liftF`

These methods will make working with our DSL a lot nicer, and will
lift KVStoreA[_] values into our KVStore[_] monad (note the
missing "A" in the second type).

scala mdoc:silent
import cats.free.Free.liftF

// Put returns nothing (i.e. Unit).
def put[T](key: String, value: T): KVStore[Unit] =
  liftF[KVStoreA, Unit](Put[T](key, value))

// Get returns a T value.
def get[T](key: String): KVStore[Option[T]] =
  liftF[KVStoreA, Option[T]](Get[T](key))

// Delete returns nothing (i.e. Unit).
def delete(key: String): KVStore[Unit] =
  liftF(Delete(key))

// Update composes get and set, and returns nothing.
def update[T](key: String, f: T => T): KVStore[Unit] =
  for {
    vMaybe <- get[T](key)
    _ <- vMaybe.map(v => put[T](key, f(v))).getOrElse(Free.pure(()))
  } yield ()

3. Build a program

Now that we can construct KVStore[_] values we can use our DSL to
write "programs" using a for-comprehension:

scala mdoc:silent
def program: KVStore[Option[Int]] =
  for {
    _ <- put("wild-cats", 2)
    _ <- update[Int]("wild-cats", (_ + 12))
    _ <- put("tame-cats", 5)
    n <- get[Int]("wild-cats")
    _ <- delete("tame-cats")
  } yield n

This looks like a monadic flow. However, it just builds a recursive
data structure representing the sequence of operations.

4. Write a compiler for your program

As you may have understood now, Free[_] is used to create an embedded
DSL. By itself, this DSL only represents a sequence of operations
(defined by a recursive data structure); it doesn't produce anything.

Free[_] is a programming language inside your programming language!

So, like any other programming language, we need to compile our
abstract language into an effective language and then run it.

To do this, we will use a natural transformation between type
containers. Natural transformations go between types like F[_] and
G[_] (this particular transformation would be written as
FunctionK[F,G] or as done here using the symbolic
alternative as F ~> G).

In our case, we will use a simple mutable map to represent our key
value store:

scala mdoc:silent
import cats.arrow.FunctionK
import cats.{Id, ~>}
import scala.collection.mutable

// the program will crash if a type is incorrectly specified.
def impureCompiler: KVStoreA ~> Id  =
  new (KVStoreA ~> Id) {

    // a very simple (and imprecise) key-value store
    val kvs = mutable.Map.empty[String, Any]

    def apply[A](fa: KVStoreA[A]): Id[A] =
      fa match {
        case Put(key, value) =>
          println(s"put($key, $value)")
          kvs(key) = value
          ()
        case Get(key) =>
          println(s"get($key)")
          kvs.get(key).asInstanceOf[A]
        case Delete(key) =>
          println(s"delete($key)")
          kvs.remove(key)
          ()
      }
  }

Please note this impureCompiler is impure -- it mutates kvs and
also produces logging output using println. The whole purpose of
functional programming isn't to prevent side-effects, it is just to
push side-effects to the boundaries of your system in a well-known and
controlled way.

Id[_] represents the simplest type container: the type itself. Thus,
Id[Int] is just Int. This means that our program will execute
immediately, and block until the final value can be returned.

However, we could easily use other type containers for different
behavior, such as:

  • Future[_] for asynchronous computation
  • List[_] for gathering multiple results
  • Option[_] to support optional results
  • Either[E, *] to support failure
  • a pseudo-random monad to support non-determinism
  • and so on...

5. Run your program

The final step is naturally running your program after compiling it.

Free[_] is just a recursive structure that can be seen as sequence
of operations producing other operations. In this way it is similar to
List[_]. We often use folds (e.g. foldRight) to obtain a single
value from a list; this recurses over the structure, combining its
contents.

The idea behind running a Free[_] is exactly the same. We fold the
recursive structure by:

  • consuming each operation.
  • compiling the operation into our effective language using
    impureCompiler (applying its effects if any).
  • computing next operation.
  • continue recursively until reaching a Pure state, and returning it.

This operation is called Free.foldMap:

scala
final def foldMap[M[_]](f: FunctionK[S,M])(M: Monad[M]): M[A] = ...

M must be a Monad to be flattenable (the famous monoid aspect
under Monad). As Id is a Monad, we can use foldMap.

To run your Free with previous impureCompiler:

scala mdoc
val result: Option[Int] = program.foldMap(impureCompiler)

An important aspect of foldMap is its stack-safety. It evaluates
each step of computation on the stack then unstack and restart. This
process is known as trampolining.

As long as your natural transformation is stack-safe, foldMap will
never overflow your stack. Trampolining is heap-intensive but
stack-safety provides the reliability required to use Free[_] for
data-intensive tasks, as well as infinite processes such as streams.

6. Use a pure compiler (optional)

The previous examples used an effectful natural transformation. This
works, but you might prefer folding your Free in a "purer" way. The
State data structure can be used to keep track of the program
state in an immutable map, avoiding mutation altogether.

scala mdoc:silent
import cats.data.State

type KVStoreState[A] = State[Map[String, Any], A]
val pureCompiler: KVStoreA ~> KVStoreState = new (KVStoreA ~> KVStoreState) {
  def apply[A](fa: KVStoreA[A]): KVStoreState[A] =
    fa match {
      case Put(key, value) => State.modify(_.updated(key, value))
      case Get(key) =>
        State.inspect(_.get(key).asInstanceOf[A])
      case Delete(key) => State.modify(_ - key)
    }
}

(You can see that we are again running into some places where Scala's
support for pattern matching is limited by the JVM's type erasure, but
it's not too hard to get around.)

scala mdoc:nest
val result: (Map[String, Any], Option[Int]) = program.foldMap(pureCompiler).run(Map.empty).value

Composing Free monads ADTs.

Real world applications often time combine different algebras.
The injection type class described by Swierstra in Data types à la carte
lets us compose different algebras in the context of Free.

Let's see a trivial example of unrelated ADT's getting composed as a EitherK that can form a more complex program.

scala mdoc:silent
import cats.data.EitherK
import cats.free.Free
import cats.{Id, InjectK, ~>}
import scala.collection.mutable.ListBuffer
scala mdoc:silent
/* Handles user interaction */
sealed trait Interact[A]
case class Ask(prompt: String) extends Interact[String]
case class Tell(msg: String) extends Interact[Unit]

/* Represents persistence operations */
sealed trait DataOp[A]
case class AddCat(a: String) extends DataOp[Unit]
case class GetAllCats() extends DataOp[List[String]]

Once the ADTs are defined we can formally state that a Free program is the EitherK of its Algebras.

scala mdoc:silent
type CatsApp[A] = EitherK[DataOp, Interact, A]

In order to take advantage of monadic composition we use smart constructors to lift our Algebra to the Free context.

scala mdoc:silent
class Interacts[F[_]](implicit I: InjectK[Interact, F]) {
  def tell(msg: String): Free[F, Unit] = Free.liftInject[F](Tell(msg))
  def ask(prompt: String): Free[F, String] = Free.liftInject[F](Ask(prompt))
}

object Interacts {
  implicit def interacts[F[_]](implicit I: InjectK[Interact, F]): Interacts[F] = new Interacts[F]
}

class DataSource[F[_]](implicit I: InjectK[DataOp, F]) {
  def addCat(a: String): Free[F, Unit] = Free.liftInject[F](AddCat(a))
  def getAllCats: Free[F, List[String]] = Free.liftInject[F](GetAllCats())
}

object DataSource {
  implicit def dataSource[F[_]](implicit I: InjectK[DataOp, F]): DataSource[F] = new DataSource[F]
}

ADTs are now easily composed and trivially intertwined inside monadic contexts.

scala mdoc:nest:silent
def program(implicit I : Interacts[CatsApp], D : DataSource[CatsApp]): Free[CatsApp, Unit] = {

  import I._, D._

  for {
    cat <- ask("What's the kitty's name?")
    _ <- addCat(cat)
    cats <- getAllCats
    _ <- tell(cats.toString)
  } yield ()
}

Finally we write one interpreter per ADT and combine them with a FunctionK to EitherK so they can be
compiled and applied to our Free program.

scala mdoc:invisible
def readLine(): String = "snuggles"
scala mdoc:silent
object ConsoleCatsInterpreter extends (Interact ~> Id) {
  def apply[A](i: Interact[A]) = i match {
    case Ask(prompt) =>
      println(prompt)
      readLine()
    case Tell(msg) =>
      println(msg)
  }
}

object InMemoryDatasourceInterpreter extends (DataOp ~> Id) {

  private[this] val memDataSet = new ListBuffer[String]

  def apply[A](fa: DataOp[A]) = fa match {
    case AddCat(a) => memDataSet.append(a); ()
    case GetAllCats() => memDataSet.toList
  }
}

val interpreter: CatsApp ~> Id = InMemoryDatasourceInterpreter or ConsoleCatsInterpreter

Now if we run our program and type in "snuggles" when prompted, we see something like this:

scala mdoc:silent
import DataSource._, Interacts._
scala mdoc
val evaled: Unit = program.foldMap(interpreter)

For the curious ones: what is Free in theory?

Mathematically-speaking, a free monad (at least in the programming
language context) is a construction that is left adjoint to a
forgetful functor whose domain is the category of Monads and whose
co-domain is the category of Endofunctors. Huh?

Concretely, it is just a clever construction that allows us to build a
very simple Monad from any functor
.

The above forgetful functor takes a Monad and:

  • forgets its monadic part (e.g. the flatMap function)
  • forgets its pointed part (e.g. the pure function)
  • finally keeps the functor part (e.g. the map function)

By reversing all arrows to build the left-adjoint, we deduce that the
free monad is basically a construction that:

  • takes a functor
  • adds the pointed part (e.g. pure)
  • adds the monadic behavior (e.g. flatMap)

In terms of implementation, to build a monad from a functor we use
the following classic inductive definition:

scala
sealed abstract class Free[F[_], A]
case class Pure[F[_], A](a: A) extends Free[F, A]
case class Suspend[F[_], A](a: F[Free[F, A]]) extends Free[F, A]

(This generalizes the concept of fixed point functor.)

In this representation:

  • Pure builds a Free instance from an A value (it reifies the
    pure function)
  • Suspend builds a new Free by applying F to a previous Free
    (it reifies the flatMap function)

So a typical Free structure might look like:

scala
Suspend(F(Suspend(F(Suspend(F(....(Pure(a))))))))

Free is a recursive structure. It uses A in F[A] as the
recursion "carrier" with a terminal element Pure.

From a computational point of view, Free recursive structure can be
seen as a sequence of operations.

  • Pure returns an A value and ends the entire computation.
  • Suspend is a continuation; it suspends the current computation
    with the suspension functor F (which can represent a command for
    example) and hands control to the caller. A represents a value
    bound to this computation.

Please note this Free construction has the interesting quality of
encoding the recursion on the heap instead of the stack as classic
function calls would. This provides the stack-safety we heard about
earlier, allowing very large Free structures to be evaluated safely.

For the very curious ones

If you look at implementation in cats, you will see another member of
the Free[_] ADT:

scala
case class FlatMapped[S[_], B, C](c: Free[S, C], f: C => Free[S, B]) extends Free[S, B]

FlatMapped represents a call to a subroutine c and when c is
finished, it continues the computation by calling the function f
with the result of c.

It is actually an optimization of Free structure allowing to solve a
problem of quadratic complexity implied by very deep recursive Free
computations.

It is exactly the same problem as repeatedly appending to a List[_].
As the sequence of operations becomes longer, the slower a flatMap
"through" the structure will be. With FlatMapped, Free becomes a
right-associated structure not subject to quadratic complexity.

FreeT

Often times we want to interleave the syntax tree when building a Free monad
with some other effect not declared as part of the ADT.
FreeT solves this problem by allowing us to mix building steps of the AST
with calling action in other base monad.

In the following example a basic console application is shown.
When the user inputs some text we use a separate State monad to track what the user
typed.

As we can observe in this case FreeT offers us the alternative to delegate denotations to State
monad with stronger equational guarantees than if we were emulating the State ops in our own ADT.

text
/* Detailed source-code truncated for AI context efficiency. */

Another example is more basic usage of FreeT with some context Ctx for which we provide Try interpreter,
combined with OptionT for reducing boilerplate.

scala mdoc:reset
import cats.free._
import cats._
import cats.data._
import cats.syntax.all._
import scala.util.Try

sealed trait Ctx[A]

case class Action(value: Int) extends Ctx[Int]

def op1: FreeT[Ctx, Option, Int] =
  FreeT.liftF[Ctx, Option, Int](Action(7))

def op2: FreeT[Ctx, Option, Int] =
  FreeT.liftT[Ctx, Option, Int](Some(4))

def op3: FreeT[Ctx, Option, Int] =
  FreeT.pure[Ctx, Option, Int](1)

val opComplete: FreeT[Ctx, Option, Int] =
  for {
    a <- op1
    b <- op2
    c <- op3
  } yield a + b + c


/*  Our interpreters  */

type OptTry[A] = OptionT[Try, A]

def tryInterpreter: Ctx ~> OptTry = new (Ctx ~> OptTry) {
  def apply[A](fa: Ctx[A]): OptTry[A] = {
    fa match {
      case Action(value) =>
        OptionT.liftF(Try(value))
    }
  }
}

def optTryLift: Option ~> OptTry = new (Option ~> OptTry) {
  def apply[A](fa: Option[A]): OptTry[A] = {
    fa match {
      case Some(value) =>
        OptionT(Try(Option(value)))
      case None =>
        OptionT.none
    }
  }
}

val hoisted = opComplete.hoist(optTryLift)
val evaluated = hoisted.foldMap(tryInterpreter)
val result = evaluated.value

Future Work (TODO)

There are many remarkable uses of Free[_]. In the future, we will
include some here, such as:

  • Trampoline
  • Option
  • Iteratee
  • Source
  • etc...

We will also discuss the Coyoneda Trick.

Credits

This article was written by
Pascal Voitot and edited by other
members of the Cats community.


Datatypes Functionk (`docs/datatypes/functionk.md`)

FunctionK

API Documentation: @:api(cats.arrow.FunctionK)

A FunctionK transforms values from one first-order-kinded type (a type that takes a single type
parameter, such as List or Option) into another first-order-kinded type. This transformation is
universal, meaning that a FunctionK[List, Option] will translate all List[A] values into an
Option[A] value for all possible types of A. This explanation may be easier to understand if we
first step back and talk about ordinary functions.

Ordinary Functions

Consider the following scala method:

scala mdoc:silent
def first(l: List[Int]): Option[Int] = l.headOption

This isn't a particularly helpful method, but it will work as an example. Instead of writing this as a
method, we could have written this as a function value:

scala mdoc:silent
val first: List[Int] => Option[Int] = l => l.headOption

And here, => is really just some syntactic sugar for Function1, so we could also write that as:

scala mdoc:silent:reset
val first: Function1[List[Int], Option[Int]] = l => l.headOption

Let's cut through the syntactic sugar even a little bit further. Function1 isn't really a special type.
It's just a trait that looks something like this:

scala mdoc:silent
// we are calling this `MyFunction1` so we don't collide with the actual `Function1`
trait MyFunction1[A, B] {
  def apply(a: A): B
}

So if we didn't mind being a bit verbose, we could have written our function as:

scala mdoc:silent:reset
val first: Function1[List[Int], Option[Int]] = new Function1[List[Int], Option[Int]] {
  def apply(l: List[Int]): Option[Int] = l.headOption
}

Abstracting via Generics

Recall our first method:

scala mdoc:silent:reset
def first(l: List[Int]): Option[Int] = l.headOption

The astute reader may have noticed that there's really no reason that this method needs to be tied directly to Int. We could use generics to make this a bit more general:

scala mdoc:silent:reset
def first[A](l: List[A]): Option[A] = l.headOption

But how would we represent this new first method as a =>/Function1 value? We are looking for something like a type of List[A] => Option[A] forAll A, but this isn't valid scala syntax. Function1 isn't quite the right fit, because its apply method doesn't take a generic type parameter.

Higher Kinds to the Rescue

It turns out that we can represent our universal List to Option transformation with something that looks a bit like Function1 but
that adds a type parameter to the apply method and utilizes higher kinds:

scala mdoc:silent:reset
trait MyFunctionK[F[_], G[_]] {
  def apply[A](fa: F[A]): G[A]
}

Cats provides this type as FunctionK (we used MyFunctionK for our example type to avoid confusion). So now we can write first as a FunctionK[List, Option] value:

scala mdoc:silent
import cats.arrow.FunctionK

val first: FunctionK[List, Option] = new FunctionK[List, Option] {
  def apply[A](l: List[A]): Option[A] = l.headOption
}

Syntactic Sugar

If the example above looks a bit too verbose for you, the kind-projector
compiler plugin provides a more concise syntax.
After adding the plugin to your project, you could write the first example as:

scala mdoc:silent:nest
val first: FunctionK[List, Option] = λ[FunctionK[List, Option]](_.headOption)

Cats also provides a ~> type alias for FunctionK, so an even more concise version would be:

scala mdoc:silent:nest
import cats.~>

val first: List ~> Option = λ[List ~> Option](_.headOption)

Being able to use ~> as an alias for FunctionK parallels being able to use => as an alias for Function1.

Use-cases

FunctionK tends to show up when there is abstraction over higher-kinds. For example, interpreters for free monads and free applicatives are represented as FunctionK instances.

Types with more than one type parameter

Earlier it was mentioned that FunctionK operates on first-order-kinded types (types that take a single type parameter such as List or Option). It's still possible to use FunctionK with types that would normally take more than one type parameter (such as Either) if we fix all of the type parameters except for one. For example:

scala mdoc:silent
type ErrorOr[A] = Either[String, A]

val errorOrFirst: FunctionK[List, ErrorOr] =
  λ[FunctionK[List, ErrorOr]](_.headOption.toRight("ERROR: the list was empty!"))

Natural Transformation

In category theory, a natural transformation provides a morphism between Functors while preserving the internal structure. It's one of the most fundamental notions of category theory.

If we have two Functors F and G, FunctionK[F, G] is a natural transformation via parametricity. That is, given fk: FunctionK[F, G], for all functions A => B and all fa: F[A] the following are equivalent:

scala
fk(F.map(fa)(f)) <-> G.map(fk(fa))(f)

We don't need to write a law to test the implementation of the fk for the above to be true. It's automatically given by parametricity.

Thus natural transformation can be implemented in terms of FunctionK. This is why a parametric polymorphic function FunctionK[F, G] is sometimes referred as a natural transformation. However, they are two different concepts that are not isomorphic.

For more details, Bartosz Milewski has written a great blog post titled
"Parametricity: Money for Nothing and Theorems for Free".


Datatypes Id (`docs/datatypes/id.md`)

Id

API Documentation: Id

The identity monad can be seen as the ambient monad that encodes the
effect of having no effect. It is ambient in the sense that plain pure
values are values of Id.

It is encoded as:

scala
type Id[A] = A

That is to say that the type Id[A] is just a synonym for A. We can
freely treat values of type A as values of type Id[A], and
vice-versa.

scala mdoc
import cats._

val x: Id[Int] = 1
val y: Int = x

Using this type declaration, we can treat our Id type constructor as a
Monad and as a Comonad. The pure
method, which has type A => Id[A] just becomes the identity
function. The map method from Functor just becomes function
application:

scala mdoc
import cats.Functor

val one: Int = 1
Functor[Id].map(one)(_ + 1)

Compare the signatures of map and flatMap and coflatMap:

scala
def map[A, B](fa: Id[A])(f: A => B): Id[B]
  def flatMap[A, B](fa: Id[A])(f: A => Id[B]): Id[B]
  def coflatMap[A, B](a: Id[A])(f: Id[A] => B): Id[B]

You'll notice that in the flatMap signature, since Id[B] is the same
as B for all B, we can rewrite the type of the f parameter to be
A => B instead of A => Id[B], and this makes the signatures of the
two functions the same, and, in fact, they can have the same
implementation, meaning that for Id, flatMap is also just function
application:

scala mdoc:nest
import cats.Monad

val one: Int = 1
Monad[Id].map(one)(_ + 1)
Monad[Id].flatMap(one)(_ + 1)

And that similarly, coflatMap is just function application:

scala mdoc
import cats.Comonad

Comonad[Id].coflatMap(one)(_ + 1)

Datatypes Ior (`docs/datatypes/ior.md`)

Ior

API Documentation: @:api(cats.data.Ior)

Ior represents an inclusive-or relationship between two data types.
This makes it very similar to the Either data type, which represents an "exclusive-or" relationship.
What this means, is that an Ior[A, B] (also written as A Ior B) can contain either an A, a B, or both an A and B.
Another similarity to Either is that Ior is right-biased,
which means that the map and flatMap functions will work on the right side of the Ior, in our case the B value.
You can see this in the function signature of map:

scala
def map[B, C](fa: A Ior B)(f: B => C): A Ior C

We can create Ior values using Ior.left, Ior.right and Ior.both:

scala mdoc
import cats.data._

val right = Ior.right[String, Int](3)

val left = Ior.left[String, Int]("Error")

val both = Ior.both("Warning", 3)

Cats also offers syntax enrichment for Ior. The leftIor and rightIor functions can be imported from cats.syntax.ior._:

scala mdoc:nest
import cats.syntax.all._

val right = 3.rightIor

val left = "Error".leftIor

When we look at the Monad or Applicative instances of Ior, we can see that they actually require a Semigroup instance on the left side.
This is because Ior will actually accumulate failures on the left side, very similar to how the Validated data type does.
This means we can accumulate data on the left side while also being able to short-circuit upon the first left-side-only value.
For example, sometimes, we might want to accumulate warnings together with a valid result and only halt the computation on a "hard error"
Here's an example of how we might be able to do that:

scala mdoc:reset-object:silent
import cats.syntax.all._
import cats.data.{ NonEmptyChain => Nec, Ior}


type Failures = Nec[String]

case class Username(value: String) extends AnyVal
case class Password(value: String) extends AnyVal

case class User(name: Username, pw: Password)

def validateUsername(u: String): Failures Ior Username = {
  if (u.isEmpty)
    Nec.one("Can't be empty").leftIor
  else if (u.contains("."))
    Ior.both(Nec.one("Dot in name is deprecated"), Username(u))
  else
    Username(u).rightIor
}

def validatePassword(p: String): Failures Ior Password = {
  if (p.length < 8)
    Nec.one("Password too short").leftIor
  else if (p.length < 10)
    Ior.both(Nec.one("Password should be longer"), Password(p))
  else
    Password(p).rightIor
}

def validateUser(name: String, password: String): Failures Ior User =
  (validateUsername(name), validatePassword(password)).mapN(User)

Now we're able to validate user data and also accumulate non-fatal warnings:

scala mdoc
validateUser("John", "password12")

validateUser("john.doe", "password")

validateUser("jane", "short")

To extract the values, we can use the fold method, which expects a function for each case the Ior can represent:

scala mdoc
validateUser("john.doe", "password").fold(
  errorNec => s"Error: ${errorNec.head}",
  user => s"Success: $user",
  (warnings, user) => s"Warning: ${user.name.value}; The following warnings occurred: ${warnings.show}"
)

Using with NonEmptyChain

Similar to Validated, there is also a type alias for using a NonEmptyChain on the left side.

scala mdoc:silent
import cats.data.NonEmptyChain

type IorNec[B, A] = Ior[NonEmptyChain[B], A]
scala mdoc:nest
import cats.syntax.all._, cats.data.NonEmptyChain

val left: IorNec[String, Int] = Ior.fromEither("Error".leftNec[Int])

Conversions

We can also convert our Ior to Either, Validated or Option.
All of these conversions will discard the left side value if both are available:

scala mdoc
Ior.both("Warning", 42).toEither

Datatypes Iort (`docs/datatypes/iort.md`)

IorT

API Documentation: @:api(cats.data.IorT)

IorT[F[_], A, B] is a light wrapper on an F[Ior[A, B]]. Similar to
OptionT[F[_], A] and EitherT[F[_], A, B], it is a monad transformer for
Ior, that can be more convenient to work with than using F[Ior[A, B]]
directly.

The boilerplate

Consider the following program that uses Ior to propagate log messages when
validating an address:

scala mdoc:silent
import cats.data.Ior
import cats.data.{ NonEmptyChain => Nec }
import cats.syntax.all._
import scala.util.{Success, Try}

type Logs = Nec[String]

def parseNumber(input: String): Ior[Logs, Option[Int]] =
  Try(input.trim.toInt) match {
    case Success(number) if number > 0 => Ior.Right(Some(number))
    case Success(_) => Ior.Both(Nec.one(s"'$input' is non-positive number"), None)
    case _ => Ior.Both(Nec.one(s"'$input' is not a number"), None)
  }

def parseStreet(input: String): Ior[Logs, String] = {
  if (input.trim.isEmpty)
    Ior.Left(Nec.one(s"'$input' is not a street"))
  else
    Ior.Right(input)
}

def numberToString(number: Option[Int]): Ior[Logs, String] =
  number match {
    case Some(n) => Ior.Right(n.toString)
    case None => Ior.Both(Nec.one("used default address number"), "n/a")
  }

def addressProgram(numberInput: String, streetInput: String): Ior[Logs, String] =
  for {
    number <- parseNumber(numberInput)
    street <- parseStreet(streetInput)
    sNumber <- numberToString(number)
  } yield s"$sNumber, $street"

Due to the monadic nature of Ior combining the results of parseNumber,
parseStreet, and numberToString can be as concise as a for-comprehension.
As the following examples demonstrate, log messages of the different processing
steps are combined when using flatMap.

scala mdoc
addressProgram("7", "Buckingham Palace Rd")
addressProgram("SW1W", "Buckingham Palace Rd")
addressProgram("SW1W", "")

Suppose parseNumber, parseStreet, and numberToString are rewritten to be
asynchronous and return Future[Ior[Logs, *]] instead. The for-comprehension
can no longer be used since addressProgram must now compose Future and
Ior together, which means that the error handling must be performed
explicitly to ensure that the proper types are returned:

scala mdoc:silent
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

def parseNumberAsync(input: String): Future[Ior[Logs, Option[Int]]] =
  Future.successful(parseNumber(input))

def parseStreetAsync(input: String): Future[Ior[Logs, String]] =
  Future.successful(parseStreet(input))

def numberToStringAsync(number: Option[Int]): Future[Ior[Logs, String]] =
  Future.successful(numberToString(number))

def programHelper(number: Option[Int], streetInput: String): Future[Ior[Logs, String]] =
  parseStreetAsync(streetInput).flatMap { streetIor =>
    numberToStringAsync(number).map { sNumberIor =>
      for {
        street <- streetIor
        sNumber <- sNumberIor
      } yield s"$sNumber, $street"
    }
  }

def addressProgramAsync(numberInput: String, streetInput: String): Future[Ior[Logs, String]] =
  parseNumberAsync(numberInput).flatMap {
    case Ior.Left(logs) => Future.successful(Ior.Left(logs))
    case Ior.Right(number) => programHelper(number, streetInput)
    case b @ Ior.Both(_, number) => programHelper(number, streetInput).map(s => b.flatMap(_ => s))
  }

To keep some readability the program was split in two parts, otherwise code
would be repeated. Note that when parseNumberAsync returns an Ior.Both it
is necessary to combine it with the result of programHelper, otherwise some
log messages would be lost.

scala mdoc
import scala.concurrent.Await
import scala.concurrent.duration._

Await.result(addressProgramAsync("7", "Buckingham Palace Rd"), 1.second)
Await.result(addressProgramAsync("SW1W", "Buckingham Palace Rd"), 1.second)
Await.result(addressProgramAsync("SW1W", ""), 1.second)

IorT to the rescue

The program of the previous section can be re-written using IorT as follows:

scala mdoc:silent
import cats.data.IorT

def addressProgramAsyncIorT(numberInput: String, streetInput: String): IorT[Future, Logs, String] =
  for {
    number <- IorT(parseNumberAsync(numberInput))
    street <- IorT(parseStreetAsync(streetInput))
    sNumber <- IorT(numberToStringAsync(number))
  } yield s"$sNumber, $street"

This version of addressProgramAsync is almost as concise as the
non-asynchronous version. Note that when F is a monad, then IorT will also
form a monad, allowing monadic combinators such as flatMap to be used in
composing IorT values.

scala mdoc
Await.result(addressProgramAsyncIorT("7", "Buckingham Palace Rd").value, 1.second)
Await.result(addressProgramAsyncIorT("SW1W", "Buckingham Palace Rd").value, 1.second)
Await.result(addressProgramAsyncIorT("SW1W", "").value, 1.second)

Looking back at the implementation of parseStreet the return type could be
Either[Logs, String] instead. Thinking of situations like this, where not all
the types match, IorT provides factory methods of IorT[F, A, B] from:

  • A, B or both
  • F[A], F[B] or both
  • Ior[A, B] or F[Ior[A, B]]
  • Either[A, B] or F[Either[A, B]]
  • Option[B] or F[Option[B]]
  • A Boolean test

From `A` and/or `B` to `IorT[F, A, B]`

To obtain a left version of IorT when given an A use IorT.leftT. When
given a B a right version of IorT can be obtained with IorT.rightT (which
is an alias for IorT.pure). Given both an A and a B use IorT.bothT.

Note the two styles for providing the IorT missing type parameters. The first
three expressions only specify not inferable types, while the last expression
specifies all types.

scala mdoc:nest
val number = IorT.rightT[Option, String](5)
val error = IorT.leftT[Option, Int]("Not a number")
val weirdNumber = IorT.bothT[Option]("Not positive", -1)

val numberPure: IorT[Option, String, Int] = IorT.pure(5)

From `F[A]` and/or `F[B]` to `IorT[F, A, B]`

Similarly, use IorT.left, IorT.right, IorT.both to convert an F[A]
and/or F[B] into an IorT. It is also possible to use IorT.liftF as an
alias for IorT.right.

scala mdoc:silent:nest
val numberF: Option[Int] = Some(5)
val errorF: Option[String] = Some("Not a number")

val warningF: Option[String] = Some("Not positive")
val weirdNumberF: Option[Int] = Some(-1)

val number: IorT[Option, String, Int] = IorT.right(numberF)
val error: IorT[Option, String, Int] = IorT.left(errorF)
val weirdNumber: IorT[Option, String, Int] = IorT.both(warningF, weirdNumberF)

From `Ior[A, B]` or `F[Ior[A, B]]` to `IorT[F, A, B]`

Use IorT.fromIor to a lift a value of Ior[A, B] into IorT[F, A, B]. An
F[Ior[A, B]] can be converted into IorT using the IorT constructor.

scala mdoc:silent:nest
val numberIor: Ior[String, Int] = Ior.Right(5)
val errorIor: Ior[String, Int] = Ior.Left("Not a number")
val weirdNumberIor: Ior[String, Int] = Ior.both("Not positive", -1)
val numberFIor: Option[Ior[String, Int]] = Option(Ior.Right(5))

val number: IorT[Option, String, Int] = IorT.fromIor(numberIor)
val error: IorT[Option, String, Int] = IorT.fromIor(errorIor)
val weirdNumber: IorT[Option, String, Int] = IorT.fromIor(weirdNumberIor)
val numberF: IorT[Option, String, Int] = IorT(numberFIor)

From `Either[A, B]` or `F[Either[A, B]]` to `IorT[F, A, B]`

Use IorT.fromEither or IorT.fromEitherF to create a value of
IorT[F, A, B] from an Either[A, B] or a F[Either[A, B]], respectively.

scala mdoc:silent:nest
val numberEither: Either[String, Int] = Right(5)
val errorEither: Either[String, Int] = Left("Not a number")
val numberFEither: Option[Either[String, Int]] = Option(Right(5))

val number: IorT[Option, String, Int] = IorT.fromEither(numberEither)
val error: IorT[Option, String, Int] = IorT.fromEither(errorEither)
val numberF: IorT[Option, String, Int] = IorT.fromEitherF(numberFEither)

From `Option[B]` or `F[Option[B]]` to `IorT[F, A, B]`

An Option[B] or an F[Option[B]], along with a default value, can be passed
to IorT.fromOption and IorT.fromOptionF, respectively, to produce an
IorT. For F[Option[B]] and default F[A], there is IorT.fromOptionM.

scala mdoc:silent:nest
val numberOption: Option[Int] = None
val numberFOption: List[Option[Int]] = List(None, Some(2), None, Some(5))

val number = IorT.fromOption[List](numberOption, "Not defined")
val numberF = IorT.fromOptionF(numberFOption, "Not defined")
val numberM = IorT.fromOptionM(numberFOption, List("Not defined"))

Creating an `IorT[F, A, B]` from a `Boolean` test

IorT.cond allows concise creation of an IorT[F, A, B] based on a Boolean
test, an A and a B. Similarly, IorT.condF uses F[A] and F[B].

scala mdoc:silent:nest
val number: Int = 10
val informedNumber: IorT[Option, String, Int] = IorT.cond(number % 10 != 0, number, "Number is multiple of 10")
val uninformedNumber: IorT[Option, String, Int] = IorT.condF(number % 10 != 0, Some(number), None)

Extracting an `F[Ior[A, B]]` from an `IorT[F, A, B]`

Use the value method defined on IorT to retrieve the underlying
F[Ior[A, B]]:

scala mdoc:silent:nest
val errorT: IorT[Option, String, Int] = IorT.leftT("Not a number")

val error: Option[Ior[String, Int]] = errorT.value

Datatypes Kleisli (`docs/datatypes/kleisli.md`)

Kleisli

API Documentation: @:api(cats.data.Kleisli)

Kleisli enables composition of functions that return a monadic value, for instance an Option[Int]
or a Either[String, List[Double]], without having functions take an Option or Either as a parameter,
which can be strange and unwieldy.

We may also have several functions which depend on some environment and want a nice way to compose these functions
to ensure they all receive the same environment. Or perhaps we have functions which depend on their own "local"
configuration and all the configurations together make up a "global" application configuration. How do we
have these functions play nice with each other despite each only knowing about their own local requirements?

These situations are where Kleisli is immensely helpful.

Functions

One of the most useful properties of functions is that they compose. That is, given a function
A => B and a function B => C, we can combine them to create a new function A => C. It is through
this compositional property that we are able to write many small functions and compose them together
to create a larger one that suits our needs.

scala mdoc:silent
val twice: Int => Int =
  x => x * 2

val countCats: Int => String =
  x => if (x == 1) "1 cat" else s"$x cats"

val twiceAsManyCats: Int => String =
  twice andThen countCats // equivalent to: countCats compose twice

Thus.

scala mdoc
twiceAsManyCats(1) // "2 cats"

Sometimes, our functions will need to return monadic values. For instance, consider the following set of functions.

scala mdoc:silent
val parse: String => Option[Int] =
  s => if (s.matches("-?[0-9]+")) Some(s.toInt) else None

val reciprocal: Int => Option[Double] =
  i => if (i != 0) Some(1.0 / i) else None

As it stands we cannot use Function1.compose (or Function1.andThen) to compose these two functions.
The output type of parse is Option[Int] whereas the input type of reciprocal is Int.

This is where Kleisli comes into play.

Kleisli

At its core, Kleisli[F[_], A, B] is just a wrapper around the function A => F[B]. Depending on the
properties of the F[_], we can do different things with Kleislis. For instance, if F[_] has a
FlatMap[F] instance (we can call flatMap on F[A] values), we can
compose two Kleislis much like we can two functions.

scala mdoc:silent
import cats.FlatMap
import cats.syntax.all._

final case class Kleisli[F[_], A, B](run: A => F[B]) {
  def compose[Z](k: Kleisli[F, Z, A])(implicit F: FlatMap[F]): Kleisli[F, Z, B] =
    Kleisli[F, Z, B](z => k.run(z).flatMap(run))
}

Returning to our earlier example:

scala mdoc:silent:nest
// Bring in cats.FlatMap[Option] instance
import cats.syntax.all._

val parse: Kleisli[Option,String,Int] =
  Kleisli((s: String) => if (s.matches("-?[0-9]+")) Some(s.toInt) else None)

val reciprocal: Kleisli[Option,Int,Double] =
  Kleisli((i: Int) => if (i != 0) Some(1.0 / i) else None)

val parseAndReciprocal: Kleisli[Option,String,Double] =
  reciprocal.compose(parse)

Kleisli#andThen can be defined similarly.

It is important to note that the F[_] having a FlatMap (or a Monad) instance is not a hard requirement -
we can do useful things with weaker requirements. Such an example would be Kleisli#map, which only requires
that F[_] have a Functor instance (e.g. is equipped with map: F[A] => (A => B) => F[B]).

scala mdoc:silent:nest
import cats.Functor

final case class Kleisli[F[_], A, B](run: A => F[B]) {
  def map[C](f: B => C)(implicit F: Functor[F]): Kleisli[F, A, C] =
    Kleisli[F, A, C](a => F.map(run(a))(f))
}

Below are some more methods on Kleisli that can be used as long as the constraint on F[_]
is satisfied.

text
Method    | Constraint on `F[_]`
--------- | -------------------
andThen   | FlatMap
compose   | FlatMap
flatMap   | FlatMap
lower     | Monad
map       | Functor
traverse  | Applicative

Type class instances

The type class instances for Kleisli, like that for functions, often fix the input type (and the F[_]) and leave
the output type free. What type class instances it has tends to depend on what instances the F[_] has. For
instance, Kleisli[F, A, B] has a Functor instance as long as the chosen F[_] does. It has a Monad
instance as long as the chosen F[_] does. The instances in Cats are laid out in a way such that implicit
resolution will pick up the most specific instance it can (depending on the F[_]).

An example of a Monad instance for Kleisli is shown below.

Note: the example below assumes usage of the kind-projector compiler plugin and will not compile if it is not being used in a project.

scala mdoc:silent
import cats.syntax.all._

// We can define a FlatMap instance for Kleisli if the F[_] we chose has a FlatMap instance
// Note the input type and F are fixed, with the output type left free
implicit def kleisliFlatMap[F[_], Z](implicit F: FlatMap[F]): FlatMap[Kleisli[F, Z, *]] =
  new FlatMap[Kleisli[F, Z, *]] {
    def flatMap[A, B](fa: Kleisli[F, Z, A])(f: A => Kleisli[F, Z, B]): Kleisli[F, Z, B] =
      Kleisli(z => fa.run(z).flatMap(a => f(a).run(z)))

    def map[A, B](fa: Kleisli[F, Z, A])(f: A => B): Kleisli[F, Z, B] =
      Kleisli(z => fa.run(z).map(f))

    def tailRecM[A, B](a: A)(f: A => Kleisli[F, Z, Either[A, B]]) =
      Kleisli[F, Z, B]({ z => FlatMap[F].tailRecM(a) { f(_).run(z) } })
  }

Below is a table of some of the type class instances Kleisli can have depending on what instances F[_] has.

text
Type class     | Constraint on `F[_]`
-------------- | -------------------
Functor        | Functor
Apply          | Apply
Applicative    | Applicative
FlatMap        | FlatMap
Monad          | Monad
Arrow          | Monad
Split          | FlatMap
Strong         | Functor
SemigroupK*    | FlatMap
MonoidK*       | Monad

*These instances only exist for Kleisli arrows with identical input and output types; that is,
Kleisli[F, A, A] for some type A. These instances use Kleisli composition as the combine operation,
and Monad.pure as the empty value.

Also, there is an instance of Monoid[Kleisli[F, A, B]] if there is an instance of Monoid[F[B]].
Monoid.combine here creates a new Kleisli arrow which takes an A value and feeds it into each
of the combined Kleisli arrows, which together return two F[B] values. Then, they are combined into one
using the Monoid[F[B]] instance.

Other uses

Monad Transformers

Many data types have a monad transformer equivalent that allows us to compose the Monad instance of the data
type with any other Monad instance. For instance, OptionT[F[_], A] allows us to compose the monadic properties
of Option with any other F[_], such as a List. This allows us to work with nested contexts/effects in a
nice way (for example, in for-comprehensions).

Kleisli can be viewed as the monad transformer for functions. Recall that at its essence, Kleisli[F, A, B]
is just a function A => F[B], with niceties to make working with the value we actually care about, the B, easy.
Kleisli allows us to take the effects of functions and have them play nice with the effects of any other F[_].

This may raise the question, what exactly is the "effect" of a function?

Well, if we take a look at any function, we can see it takes some input and produces some output with it, without
having touched the input (assuming the function is pure, i.e.
referentially transparent).
That is, we take a read-only value, and produce some value with it. For this reason, the type class instances for
functions often refer to the function as a Reader. For instance, it is common to hear about the Reader monad.
In the same spirit, Cats defines a Reader type alias along the lines of:

scala mdoc:silent
// We want A => B, but Kleisli provides A => F[B]. To make the types/shapes match,
// we need an F[_] such that providing it a type A is equivalent to A
// This can be thought of as the type-level equivalent of the identity function
type Id[A] = A

type Reader[A, B] = Kleisli[Id, A, B]
object Reader {
  // Lifts a plain function A => B into a Kleisli, giving us access
  // to all the useful methods and type class instances
  def apply[A, B](f: A => B): Reader[A, B] = Kleisli[Id, A, B](f)
}

type ReaderT[F[_], A, B] = Kleisli[F, A, B]
val ReaderT = Kleisli

The ReaderT value alias exists to allow users to use the Kleisli companion object as if it were ReaderT, if
they were so inclined.

The topic of functions as a read-only environment brings us to our next common use case of Kleisli - configuration.

Configuration

Functional programming advocates the creation of programs and modules by composing smaller, simpler modules. This
philosophy intentionally mirrors that of function composition - write many small functions, and compose them
to build larger ones. After all, our programs are just functions.

Let's look at some example modules, where each module has its own configuration that is validated by a function.
If the configuration is good, we return a Some of the module, otherwise a None. This example uses Option for
simplicity - if you want to provide error messages or other failure context, consider using Either instead.

scala mdoc:silent
case class DbConfig(url: String, user: String, pass: String)
trait Db
object Db {
  val fromDbConfig: Kleisli[Option, DbConfig, Db] = ???
}

case class ServiceConfig(addr: String, port: Int)
trait Service
object Service {
  val fromServiceConfig: Kleisli[Option, ServiceConfig, Service] = ???
}

We have two independent modules, a Db (allowing access to a database) and a Service (supporting an API to provide
data over the web). Both depend on their own configuration parameters. Neither know or care about the other, as it
should be. However our application needs both of these modules to work. It is plausible we then have a more global
application configuration.

scala mdoc:silent
case class AppConfig(dbConfig: DbConfig, serviceConfig: ServiceConfig)

class App(db: Db, service: Service)

As it stands, we cannot use both Kleisli validation functions together nicely - one takes a DbConfig, the
other a ServiceConfig. That means the FlatMap (and by extension, the Monad) instances differ (recall the
input type is fixed in the type class instances). However, there is a nice function on Kleisli called local.

scala mdoc:silent:nest
final case class Kleisli[F[_], A, B](run: A => F[B]) {
  def local[AA](f: AA => A): Kleisli[F, AA, B] = Kleisli(f.andThen(run))
}

What local allows us to do is essentially "expand" our input type to a more "general" one. In our case, we
can take a Kleisli that expects a DbConfig or ServiceConfig and turn it into one that expects an AppConfig,
as long as we tell it how to go from an AppConfig to the other configs.

Now we can create our application config validator!

scala mdoc:silent:nest
final case class Kleisli[F[_], Z, A](run: Z => F[A]) {
  def flatMap[B](f: A => Kleisli[F, Z, B])(implicit F: FlatMap[F]): Kleisli[F, Z, B] =
    Kleisli(z => F.flatMap(run(z))(a => f(a).run(z)))

  def map[B](f: A => B)(implicit F: Functor[F]): Kleisli[F, Z, B] =
    Kleisli(z => F.map(run(z))(f))

  def local[ZZ](f: ZZ => Z): Kleisli[F, ZZ, A] = Kleisli(f.andThen(run))
}

case class DbConfig(url: String, user: String, pass: String)
trait Db
object Db {
  val fromDbConfig: Kleisli[Option, DbConfig, Db] = ???
}

case class ServiceConfig(addr: String, port: Int)
trait Service
object Service {
  val fromServiceConfig: Kleisli[Option, ServiceConfig, Service] = ???
}

case class AppConfig(dbConfig: DbConfig, serviceConfig: ServiceConfig)

class App(db: Db, service: Service)

def appFromAppConfig: Kleisli[Option, AppConfig, App] =
  for {
    db <- Db.fromDbConfig.local[AppConfig](_.dbConfig)
    sv <- Service.fromServiceConfig.local[AppConfig](_.serviceConfig)
  } yield new App(db, sv)

What if we need a module that doesn't need any config validation, say a strategy to log events? We would have such a
module be instantiated from a config directly, without an Option - we would have something like
Kleisli[Id, LogConfig, Log] (alternatively, Reader[LogConfig, Log]). However, this won't play nice with our other
Kleislis since those use Option instead of Id.

We can define a lift method on Kleisli (available already on Kleisli in Cats) that takes a type parameter G[_]
such that G has an Applicative instance and lifts a Kleisli value such that its output type is G[F[B]]. This
allows us to then lift a Reader[A, B] into a Kleisli[G, A, B]. Note that lifting a Reader[A, B] into some G[_]
is equivalent to having a Kleisli[G, A, B] since Reader[A, B] is just a type alias for Kleisli[Id, A, B], and
type Id[A] = A so G[Id[A]] is equivalent to G[A].


Datatypes Nel (`docs/datatypes/nel.md`)

NonEmptyList

API Documentation: @:api(cats.data.NonEmptyList)

Motivation

We start with two examples of NonEmptyLists

Usage in `Validated` and `Ior`

If you have had the opportunity of taking a look to
Validated or Ior, you'll find that a
common case is to use NonEmptyList with one of these data
structures.

Why? Because it fits nicely in the error reporting cases. As stated by
its name, NonEmptyList is a specialized data type that has at
least one element. Otherwise it behaves like a normal List. For
sum types like Validated (and Ior), it does not make sense to have
a Invalid with no errors: no errors means it is a Valid! By using
NonEmptyList, we explicitly say in the type that:

If it is a Invalid, then there is at least one error.

This is much more precise and we don't have to wonder whether the list
of errors might be empty when reporting them later on.

Avoiding `Option` by demanding more specific arguments

As functional programmers, we naturally shy away from partial
functions that can throw exceptions like the famous head method on,
e.g., List.

Let's take as an example a method that calculates the average:

scala mdoc:silent
def average(xs: List[Int]): Double = {
  xs.sum / xs.length.toDouble
}

Clearly, this is not a valid definition for empty lists, because
division by zero will throw an exception. To fix this, one way is to
return an Option instead of a Double right away:

scala mdoc:silent:nest
def average(xs: List[Int]): Option[Double] = if (xs.isEmpty) {
  None
} else {
  Some(xs.sum / xs.length.toDouble)
}

That works and is safe, but this only masks the problem of accepting
invalid input
. By using Option, we extend the average function
with the logic to handle empty lists. Additionally, all callers have
to handle the Option cases, maybe over and over again. While better
than failing with an exception, this is far from perfect.

Instead what we would like to express is that average does not make
sense at all for an empty list. Luckily, cats defines the
NonEmptyList. As the name says, this represents a list that
cannot, by construction, be empty. So given a NonEmptyList[A] you
can be sure that there is at least one A in there.

Let's see how that impacts your average method:

scala mdoc:silent:nest
import cats.data.NonEmptyList
def average(xs: NonEmptyList[Int]): Double = {
  xs.reduceLeft(_+_) / xs.length.toDouble
}

With that, average is free of any "domain invariant validation" and
instead can focus on the actual logic of computing the average of the
list. This ties in nicely with the recommendation of shifting your
validation to the very borders of your program, where the input enters
your system.

Structure of a NonEmptyList

NonEmptyList is defined as follows:

scala
final case class NonEmptyList[+A](head: A, tail: List[A]) {
  // Implementation elided
}

The head of the NonEmptyList will be non-empty. Meanwhile, the
tail can have zero or more elements contained in a List.

Defined for all its elements

An important trait of NonEmptyList is the totality. For List specifically,
both head and tail are partial: they are only well-defined if it
has at least one element.

NonEmptyList on the other hand, guarantees you that operations like
head and tail are defined, because constructing an empty
NonEmptyList is simply not possible!

Constructing a NonEmptyList

To construct a NonEmptyList you have different possibilities.

Using `one`

If you want to construct a collection with only one argument, use
NonEmptyList.one:

scala mdoc
NonEmptyList.one(42)

Using `of`

The NonEmptyList.of method on the companion of NonEmptyList as the signature:

scala
def of[A](head: A, tail: A*): NonEmptyList[A]

It accepts an argument list with at least one A followed by a
varargs argument for the tail. Call it like this:

scala mdoc
NonEmptyList.of(1)
NonEmptyList.of(1, 2)
NonEmptyList.of(1, 2, 3, 4)

There also is ofInitLast which takes a normal List[A] for the
prefix and a last element:

scala mdoc
NonEmptyList.ofInitLast(List(), 4)
NonEmptyList.ofInitLast(List(1,2,3), 4)

Using `fromList`

There is also NonEmptyList.fromList which returns an
Option[NonEmptyList[A]]:

scala mdoc
NonEmptyList.fromList(List())
NonEmptyList.fromList(List(1,2,3))

Last but not least, there is .toNel if you import the syntax for
list:

scala mdoc
import cats.syntax.list._
List(1,2,3).toNel

Using `fromFoldable` and `fromReducible`

Even more general, you can use NonEmptyList.fromFoldable and
NonEmptyList.fromReducible. The difference between the two is that
fromReducible can avoid the Option in the return type, because it
is only available for non-empty datastructures.

Here are some examples:

scala mdoc
import cats.syntax.all._

NonEmptyList.fromFoldable(List())
NonEmptyList.fromFoldable(List(1,2,3))

NonEmptyList.fromFoldable(Vector(42))
NonEmptyList.fromFoldable(Vector(42))

// Everything that has a Foldable instance!
NonEmptyList.fromFoldable(Either.left[String, Int]("Error"))
NonEmptyList.fromFoldable(Either.right[String, Int](42))

// Avoid the Option for things with a `Reducible` instance
import cats.data.NonEmptyVector
NonEmptyList.fromReducible(NonEmptyVector.of(1, 2, 3))

Datatypes Nested (`docs/datatypes/nested.md`)

Nested

API Documentation: @:api(cats.data.Nested)

Motivation

In day-to-day programming we quite often end up with data inside nested
effects, e.g. an integer inside an Either, which in turn is nested inside
an Option:

scala mdoc:silent
import cats.data.Validated
import cats.data.Validated.Valid
val x: Option[Validated[String, Int]] = Some(Valid(123))

This can be quite annoying to work with, as you have to traverse the nested
structure every time you want to perform a map or something similar:

scala mdoc
x.map(_.map(_.toString))

Nested can help with this by composing the two map operations into one:

scala mdoc:silent
import cats.data.Nested
import cats.syntax.all._
val nested: Nested[Option, Validated[String, *], Int] = Nested(Some(Valid(123)))
scala mdoc
nested.map(_.toString).value

In a sense, Nested is similar to monad transformers like OptionT and
EitherT, as it represents the nesting of effects inside each other. But
Nested is more general - it does not place any restriction on the type of the
two nested effects:

scala
final case class Nested[F[_], G[_], A](value: F[G[A]])

Instead, it provides a set of inference rules based on the properties of F[_]
and G[_]. For example:

  • If F[_] and G[_] are both Functors, then Nested[F, G, *] is also a
    Functor (we saw this in action in the example above)
  • If F[_] and G[_] are both Applicatives, then Nested[F, G, *] is also an
    Applicative
  • If F[_] is an ApplicativeError and G[_] is an Applicative, then
    Nested[F, G, *] is an ApplicativeError
  • If F[_] and G[_] are both Traverses, then Nested[F, G, *] is also a
    Traverse

You can see the full list of these rules in the Nested companion object.

A more interesting example

(courtesy of Channing Walton and Luka Jacobowitz via
Twitter
,
slightly adapted)

Say we have an API for creating users:

scala mdoc:silent
import scala.concurrent.Future

case class UserInfo(name: String, age: Int)
case class User(id: String, name: String, age: Int)

def createUser(userInfo: UserInfo): Future[Either[List[String], User]] =
  Future.successful(Right(User("user 123", userInfo.name, userInfo.age)))

Using Nested we can write a function that, given a list of UserInfos,
creates a list of Users:

scala mdoc:silent
import scala.concurrent.Await
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import cats.Applicative
import cats.data.Nested
import cats.syntax.all._

def createUsers(userInfos: List[UserInfo]): Future[Either[List[String], List[User]]] =
  userInfos.traverse(userInfo => Nested(createUser(userInfo))).value

val userInfos = List(
  UserInfo("Alice", 42),
  UserInfo("Bob", 99)
)
scala mdoc
Await.result(createUsers(userInfos), 1.second)

Note that if we hadn't used Nested, the behaviour of our function would have
been different, resulting in a different return type:

scala mdoc:silent
def createUsersNotNested(userInfos: List[UserInfo]): Future[List[Either[List[String], User]]] =
  userInfos.traverse(createUser)
scala mdoc
Await.result(createUsersNotNested(userInfos), 1.second)

Datatypes Oneand (`docs/datatypes/oneand.md`)

OneAnd

API Documentation: @:api(cats.data.OneAnd)

The OneAnd[F[_],A] data type represents a single element of type A
that is guaranteed to be present (head) and in addition to this a
second part that is wrapped inside an higher kinded type constructor
F[_]. By choosing the F parameter, you can model for example
non-empty lists by choosing List for F, giving:

scala mdoc:silent
import cats.data.OneAnd

type NonEmptyList[A] = OneAnd[List, A]

which used to be the implementation of non-empty lists in Cats but has
been replaced by the cats.data.NonEmptyList data type. By
having the higher kinded type parameter F[_], OneAnd is also able
to represent other "non-empty" data structures e.g.

scala mdoc:silent
type NonEmptyStream[A] = OneAnd[Stream, A]

Datatypes Optiont (`docs/datatypes/optiont.md`)

OptionT

API Documentation: @:api(cats.data.OptionT)

OptionT[F[_], A] is a light wrapper on an F[Option[A]]. Speaking technically, it is a monad transformer for Option, but you don't need to know what that means for it to be useful. OptionT can be more convenient to work with than using F[Option[A]] directly.

Reduce map boilerplate

Consider the following scenario:

scala mdoc:silent
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

val customGreeting: Future[Option[String]] = Future.successful(Some("welcome back, Lola"))

We want to try out various forms of our greetings.

scala mdoc:silent
val excitedGreeting: Future[Option[String]] = customGreeting.map(_.map(_ + "!"))

val hasWelcome: Future[Option[String]] = customGreeting.map(_.filter(_.contains("welcome")))

val noWelcome: Future[Option[String]] = customGreeting.map(_.filterNot(_.contains("welcome")))

val withFallback: Future[String] = customGreeting.map(_.getOrElse("hello, there!"))

As you can see, the implementations of all of these variations are very similar. We want to call the Option operation (map, filter, filterNot, getOrElse), but since our Option is wrapped in a Future, we first need to map over the Future.

OptionT can help remove some of this boilerplate. It exposes methods that look like those on Option, but it handles the outer map call on the Future so we don't have to:

scala mdoc:silent:nest
import cats.data.OptionT
import cats.syntax.all._

val customGreetingT: OptionT[Future, String] = OptionT(customGreeting)

val excitedGreeting: OptionT[Future, String] = customGreetingT.map(_ + "!")

val withWelcome: OptionT[Future, String] = customGreetingT.filter(_.contains("welcome"))

val noWelcome: OptionT[Future, String] = customGreetingT.filterNot(_.contains("welcome"))

val withFallback: Future[String] = customGreetingT.getOrElse("hello, there!")

From `Option[A]` and/or `F[A]` to `OptionT[F, A]`

Sometimes you may have an Option[A] and/or F[A] and want to lift them into an OptionT[F, A]. For this purpose OptionT exposes two useful methods, namely fromOption and liftF, respectively. E.g.:

scala mdoc:silent
val greetingFO: Future[Option[String]] = Future.successful(Some("Hello"))

val firstnameF: Future[String] = Future.successful("Jane")

val lastnameO: Option[String] = Some("Doe")

val ot: OptionT[Future, String] = for {
  g <- OptionT(greetingFO)
  f <- OptionT.liftF(firstnameF)
  l <- OptionT.fromOption[Future](lastnameO)
} yield s"$g $f $l"

val result: Future[Option[String]] = ot.value // Future(Some("Hello Jane Doe"))

From `A` to `OptionT[F,A]`

If you have only an A and you wish to lift it into an OptionT[F,A] assuming you have an Applicative instance for F you can use some which is an alias for pure. There also exists a none method which can be used to create an OptionT[F,A], where the Option wrapped A type is actually a None:

scala mdoc:silent
val greet: OptionT[Future,String] = OptionT.pure("Hola!")

val greetAlt: OptionT[Future,String] = OptionT.some("Hi!")

val failedGreet: OptionT[Future,String] = OptionT.none

Beyond map

Sometimes the operation you want to perform on an Future[Option[String]] might not be as simple as just wrapping the Option method in a Future.map call. For example, what if we want to greet the customer with their custom greeting if it exists but otherwise fall back to a default Future[String] greeting? Without OptionT, this implementation might look like:

scala mdoc:silent
val defaultGreeting: Future[String] = Future.successful("hello, there")

val greeting: Future[String] = customGreeting.flatMap(custom =>
  custom.map(Future.successful).getOrElse(defaultGreeting))

We can't quite turn to the getOrElse method on OptionT, because it takes a default value of type A instead of Future[A]. However, the getOrElseF method is exactly what we want:

scala mdoc:silent:nest
val greeting: Future[String] = customGreetingT.getOrElseF(defaultGreeting)

Getting to the underlying instance

If you want to get the F[Option[A]] value (in this case Future[Option[String]]) out of an OptionT instance, you can simply call value:

scala mdoc:silent:nest
val customGreeting: Future[Option[String]] = customGreetingT.value

Datatypes State (`docs/datatypes/state.md`)

State

API Documentation: @:api(cats.data.IndexedStateT)

State is a structure that provides a functional approach to handling application state. State[S, A] is basically a function S => (S, A), where S is the type that represents your state and A is the result the function produces. In addition to returning the result of type A, the function returns a new S value, which is the updated state.

Robots

Let's try to make this more concrete with an example. We have this Robot model:

scala mdoc:silent
final case class Robot(
  id: Long,
  sentient: Boolean,
  name: String,
  model: String)

We would like to generate some random Robot instances for test data.

Pseudorandom values

Scala's standard library has a built-in Random class that provides a (pseudo)random number generator (RNG). Let's use it to write a method that creates robots.

scala mdoc:silent
val rng = new scala.util.Random(0L)

def createRobot(): Robot = {
  val id = rng.nextLong()
  val sentient = rng.nextBoolean()
  val isCatherine = rng.nextBoolean()
  val name = if (isCatherine) "Catherine" else "Carlos"
  val isReplicant = rng.nextBoolean()
  val model = if (isReplicant) "replicant" else "borg"
  Robot(id, sentient, name, model)
}
scala mdoc
val robot = createRobot()

We create a single Random instance, which is mutated as a side-effect each time that we call nextLong or nextBoolean on it. This mutation makes it more difficult to reason about our code. Someone might come along and see that we have rng.nextBoolean repeated three times within a single method. They might cleverly avoid repeated code and method invocations by extracting the common code into a variable:

scala mdoc:silent:nest
val rng = new scala.util.Random(0L)

def createRobot(): Robot = {
  val id = rng.nextLong()
  val b = rng.nextBoolean()
  val sentient = b
  val isCatherine = b
  val name = if (isCatherine) "Catherine" else "Carlos"
  val isReplicant = b
  val model = if (isReplicant) "replicant" else "borg"
  Robot(id, sentient, name, model)
}
scala mdoc
val robot = createRobot()

But now the output of our program has changed! We used to have a replicant robot named Catherine, but now we have a borg robot named Carlos. It might not have been obvious, but the nextBoolean calls we were making had the side effect of mutating internal RNG state, and we were depending on that behavior.

When we can't freely refactor identical code into a common variable, the code becomes harder to reason about. In functional programming lingo, one might say that such code lacks referential transparency.

Purely functional pseudorandom values

Since mutating state caused us trouble, let's create an RNG that is immutable.

We'll use a simple RNG that can generate pseudorandom Long values based only on the previous "seed" value and some carefully chosen constants. You don't need to understand the details of this implementation for the purposes of this example, but if you'd like to know more, this is Knuth's 64-bit linear congruential generator.

scala mdoc:silent
final case class Seed(long: Long) {
  def next = Seed(long * 6364136223846793005L + 1442695040888963407L)
}

Instead of mutating the existing long value, calling next returns a new Seed instance with an updated long value.

Since the RNG isn't updating state internally, we will need to keep track of state outside of the RNG. When we call nextBoolean we will want it to return a Boolean as it did before, but we will also want it to return an updated Seed that we can use to generate our next random value.

scala mdoc:silent
def nextBoolean(seed: Seed): (Seed, Boolean) =
  (seed.next, seed.long >= 0L)

Similarly, nextLong will return an updated Seed along with a Long value.

scala mdoc:silent
def nextLong(seed: Seed): (Seed, Long) =
  (seed.next, seed.long)

Now we need to explicitly pass in the updated state as we generate each new value.

scala mdoc:silent:nest
def createRobot(seed: Seed): Robot = {
  val (seed1, id) = nextLong(seed)
  val (seed2, sentient) = nextBoolean(seed1)
  val (seed3, isCatherine) = nextBoolean(seed2)
  val name = if (isCatherine) "Catherine" else "Carlos"
  val (seed4, isReplicant) = nextBoolean(seed3)
  val model = if (isReplicant) "replicant" else "borg"
  Robot(id, sentient, name, model)
}

val initialSeed = Seed(13L)
scala mdoc
val robot = createRobot(initialSeed)

Now it is a bit more obvious that we can't extract the three nextBoolean calls into a single variable, because we are passing each one a different seed value.

However, it is a bit cumbersome to explicitly pass around all of this intermediate state. It's also a bit error-prone. It would have been easy to accidentally call nextBoolean(seed2) for both the name generation and the model generation, instead of remembering to use nextBoolean(seed3) the second time.

Cleaning it up with State

State's special power is keeping track of state and passing it along. Recall the description of State at the beginning of this document. It is basically a function S => (S, A), where S is a type representing state.

Our nextLong function takes a Seed and returns an updated Seed and a Long. It can be represented as Seed => (Seed, Long), and therefore matches the pattern S => (S, A) where S is Seed and A is Long.

Let's write a new version of nextLong using State:

scala mdoc:invisible:reset
// re-define everything to make it easier to reset mdoc
// as things like nextLong are conflicting with each other

final case class Robot(
  id: Long,
  sentient: Boolean,
  name: String,
  model: String)

final case class Seed(long: Long) {
  def next = Seed(long * 6364136223846793005L + 1442695040888963407L)
}

val initialSeed = Seed(13L)
scala mdoc:silent
import cats.data.State

val nextLong: State[Seed, Long] = State(seed =>
  (seed.next, seed.long))

The map method on State allows us to transform the A value without affecting the S (state) value. This is perfect for implementing nextBoolean in terms of nextLong.

scala mdoc:silent
val nextBoolean: State[Seed, Boolean] = nextLong.map(long =>
  long >= 0)

The flatMap method on State[S, A] lets you use the result of one State in a subsequent State. The updated state (S) after the first call is passed into the second call. These flatMap and map methods allow us to use State in for-comprehensions:

scala mdoc:silent
val createRobot: State[Seed, Robot] =
  for {
    id <- nextLong
    sentient <- nextBoolean
    isCatherine <- nextBoolean
    name = if (isCatherine) "Catherine" else "Carlos"
    isReplicant <- nextBoolean
    model = if (isReplicant) "replicant" else "borg"
  } yield Robot(id, sentient, name, model)

At this point, we have not yet created a robot; we have written instructions for creating a robot. We need to pass in an initial seed value, and then we can call value to actually create the robot:

scala mdoc:nest
val (finalState, robot) = createRobot.run(initialSeed).value

If we only care about the robot and not the final state, then we can use runA:

scala mdoc:nest
val robot = createRobot.runA(initialSeed).value

The createRobot implementation reads much like the imperative code we initially wrote for the mutable RNG. However, this implementation is free of mutation and side-effects. Since this code is referentially transparent, we can perform the refactoring that we tried earlier without affecting the result:

scala mdoc:silent:nest
val createRobot: State[Seed, Robot] = {
  val b = nextBoolean

  for {
    id <- nextLong
    sentient <- b
    isCatherine <- b
    name = if (isCatherine) "Catherine" else "Carlos"
    isReplicant <- b
    model = if (isReplicant) "replicant" else "borg"
  } yield Robot(id, sentient, name, model)
}
scala mdoc:nest
val robot = createRobot.runA(initialSeed).value

This may seem surprising, but keep in mind that b isn't simply a Boolean. It is a function that takes a seed and returns a Boolean, threading state along the way. Since the seed that is being passed into b changes from line to line, so do the returned Boolean values.

Interleaving effects

Let's expand on the above example; assume that our random number generator works asynchronously by fetching results from a remote server:

scala mdoc:silent
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

final case class AsyncSeed(long: Long) {
  def next = Future(AsyncSeed(long * 6364136223846793005L + 1442695040888963407L))
}

Using a proper IO data type would be ideal, but Future serves our purpose here.

We now need to redefine our nextLong action:

scala mdoc:fail
val nextLong: State[AsyncSeed, Future[Long]] = State { seed =>
  (seed.next, seed.long)
}

Oops! That doesn't work: State[S, A] requires that we return a pure next S in the State.apply constructor. We could define nextLong as State[Future[AsyncSeed], Future[Long]], but that would get us into even more trouble:

scala mdoc:fail
val nextLong: State[Future[AsyncSeed], Future[Long]] = State { seedF =>
  seedF.map { seed =>
    (seed.next, seed.long)
  }
}

The seed that State.apply passes in is now a Future, so we must map it. But we can't return a Future[(Future[S], [A])]; so what do we do?

Luckily, State[S, A] is an alias for StateT[Eval, S, A] - a monad transformer defined as StateT[F[_], S, A]. This data type represents computations of the form S => F[(S, A)].

If we plug in our concrete types, we get AsyncSeed => Future[(AsyncSeed, A)], which is something we can work with:

scala mdoc:silent
import cats.data.StateT
import cats.instances.future._
import scala.concurrent.ExecutionContext.Implicits.global

val nextLong: StateT[Future, AsyncSeed, Long] = StateT { seed =>
  seed.next zip Future.successful(seed.long)
}

Now, what do we get back if we invoke run on our nextLong action?

scala mdoc
nextLong.run(AsyncSeed(0))

Since every intermediate computation returns a Future, the composite computation returns a Future as well. To summarize, StateT[F[_], S, A] allows us to interleave effects of type F[_] in the computations wrapped by it.

It should be noted that different combinators on StateT impose different constraints on F; for example, map only requires that F has a Functor instance, but flatMap naturally requires F to have a FlatMap instance. Have a look at the method signatures for the details.

Changing States

More complex, stateful computations cannot be easily modeled by a single type. For example, let's try to model a door's state:

scala mdoc:silent
sealed trait DoorState
case object Open extends DoorState
case object Closed extends DoorState

case class Door(state: DoorState)

def open: State[DoorState, Unit] = ???
def close: State[DoorState, Unit] = ???

We would naturally expect that open would only operate on doors that are Closed, and vice-versa. However, to implement these methods currently, we have to pattern-match on the state:

scala mdoc:silent
val openImpl: State[DoorState, Unit] = State { doorState =>
  doorState match {
    case Closed => (Open, ())
    case Open   => ??? // What now?
  }
}

This puts us in the awkward situation of deciding how to handle invalid states; what's the appropriate behavior? Should we just leave the door open? Should we return a failure? That would mean that our return type needs to be modified.

The most elegant solution would be to model this requirement statically using types, and luckily, StateT is an alias for another type: IndexedStateT[F[_], SA, SB, A].

This data type models a stateful computation of the form SA => F[(SB, A)]; that's a function that receives an initial state of type SA and results in a state of type SB and a result of type A, using an effect of F.

So, let's model our typed door:

scala mdoc:silent:nest
import cats.Eval
import cats.data.IndexedStateT

def open: IndexedStateT[Eval, Closed.type, Open.type, Unit] = IndexedStateT.set(Open)
def close: IndexedStateT[Eval, Open.type, Closed.type, Unit] = IndexedStateT.set(Closed)

We can now reject, at compile time, sequences of open and close that are invalid:

scala mdoc:fail
val invalid = for {
  _ <- open
  _ <- close
  _ <- close
} yield ()

While valid sequences will be accepted:

scala mdoc
val valid = for {
  _ <- open
  _ <- close
  _ <- open
} yield ()

Note that the inferred type of valid correctly models that this computation can be executed only with an initial Closed state.

scala mdoc:fail
valid.run(Open)
scala mdoc
valid.run(Closed)

Datatypes Statet (`docs/datatypes/statet.md`)

StateT

API Documentation: @:api(cats.data.IndexedStateT)

StateT[F[_], S, A] is a data type that generalizes State with the
ability to compose with effects in F[_]. Because StateT is defined
in terms of F, it is a monad only if F is a monad. Additionally,
StateT may acquire new capabilities via F: for example, if F is
capable of error handling via MonadThrow[F], then Cats derives an
instance of MonadThrow[StateT[F, S, *]].

The type parameters are:

  • F[_] represents the effect in which the computation is performed.
  • S represents the underlying state, shared between each step of the
    state machine.
  • A represents the return value.

It can be seen as a way to add the capability to manipulate a shared
state to an existing computation in the context of F.

This definition could be confusing, but it will become clear after
learning the State monad and by the example below.

StateT and State Relationship

StateT is a monad transformer for
State, in
particular State is
defined as a StateT with
Eval as the effect
F.

scala mdoc:silent
import cats.data.StateT
import cats.Eval

type State[S, A] = StateT[Eval, S, A]

Therefore, StateT exposes the same methods of
State, such as:
modify, get and set. Plus additional methods, that handles
effectful computations, eg: modifyF, setF and liftF.

Example: Table Reservation System

In this example, we are going to model a Table Reservation System. To
do so, we need to keep track of the tables and the current
reservations for each of them. The end-user can then try to insert a
booking for a specific table and time. If such a table is available,
then the booking is placed and the state is updated, otherwise, an
error is returned.

To simplify the logic, for each reservation we will just consider a
single LocalTime starting at the beginning of the hour.

Let's start with defining the type alias for the effect type:

scala mdoc:silent:reset
import cats.data.{StateT, NonEmptyList}
import cats.syntax.all._
import java.time.LocalTime

type ThrowableOr[A] = Either[Throwable, A]

We will use an Either[Throwable, A] to model either success Right(a) or failure Left(ex).

Now, we need to implement/define:

  • The type representing the reservation.
  • The type representing the state of the Table Reservation System. It
    will wrap around a collection of Reservations.
  • An initial state, that will be just empty (no reservations).
  • A custom Throwable to be used in case of an error.
  • The logic for the booking insertion. We can take advantage of the
    method modifyF later on to apply it to the system state.

In addition, we can implement a simple function that will evaluate a
NonEmptyList of reservations, inserting them one by one.

scala mdoc:silent
object TableReservationSystem {

  final case class ReservationId(tableNumber: Int, hour: LocalTime)
  final case class Reservation(id: ReservationId, name: String)
  final case class Reservations(reservations: List[Reservation]) {
    def insert(reservation: Reservation): ThrowableOr[Reservations] =
      if (reservations.exists(r => r.id == reservation.id))
        Left(new TableAlreadyReservedException(reservation))
      else Right(Reservations(reservations :+ reservation))
  }

  final class TableAlreadyReservedException(
      reservation: Reservation
  ) extends RuntimeException(
        s"${reservation.name} cannot be added because table number ${reservation.id.tableNumber} is already reserved for the ${reservation.id.hour}"
      )

  val emptyReservationSystem: Reservations = Reservations(List.empty)

  def insertBooking(
      reservation: Reservation
  ): StateT[ThrowableOr, Reservations, Unit] =
    StateT.modifyF[ThrowableOr, Reservations](_.insert(reservation))

  def processBookings(
      bookings: NonEmptyList[Reservation]
  ): ThrowableOr[Reservations] =
    bookings
      .traverse_(insertBooking)
      .runS(emptyReservationSystem)
}

That's it, we can finally test the code above providing a simple
example input and print out the result.

text
/* Detailed source-code truncated for AI context efficiency. */

The full source code of this example can be found at this
gist
or scastie


Datatypes Validated (`docs/datatypes/validated.md`)

Validated

API Documentation: @:api(cats.data.Validated)

Imagine you are filling out a web form to signup for an account. You input your username and password and submit.
Response comes back saying your username can't have dashes in it, so you make some changes and resubmit. Can't
have special characters either. Change, resubmit. Passwords need to have at least one capital letter. Change,
resubmit. Password needs to have at least one number.

It would be nice to have all of these errors be reported simultaneously. That the username can't have dashes can
be validated separately from it not having special characters, as well as from the password needing to have certain
requirements. A misspelled (or missing) field in a config can be validated separately from another field not being
well-formed.

Enter Validated.

A first approach

You'll note firsthand that Validated is very similar to Either because it also has two possible values: errors on the left side or successful computations on the right side.

Signature of the structure is as follows:

scala
sealed abstract class Validated[+E, +A] extends Product with Serializable {
  // Implementation elided
}

And its projections:

scala
final case class Valid[+A](a: A) extends Validated[Nothing, A]
final case class Invalid[+E](e: E) extends Validated[E, Nothing]

Before diving into Validated, let's take a look at an Either based first approach to address our validation necessity.

Our data will be represented this way:

scala mdoc:silent
final case class RegistrationData(username: String, password: String, firstName: String, lastName: String, age: Int)

And our error model:

scala mdoc:silent
sealed trait DomainValidation {
  def errorMessage: String
}

case object UsernameHasSpecialCharacters extends DomainValidation {
  def errorMessage: String = "Username cannot contain special characters."
}

case object PasswordDoesNotMeetCriteria extends DomainValidation {
  def errorMessage: String = "Password must be at least 10 characters long, including an uppercase and a lowercase letter, one number and one special character."
}

case object FirstNameHasSpecialCharacters extends DomainValidation {
  def errorMessage: String = "First name cannot contain spaces, numbers or special characters."
}

case object LastNameHasSpecialCharacters extends DomainValidation {
  def errorMessage: String = "Last name cannot contain spaces, numbers or special characters."
}

case object AgeIsInvalid extends DomainValidation {
  def errorMessage: String = "You must be aged 18 and not older than 75 to use our services."
}

We have our RegistrationData case class that will hold the information the user has submitted, alongside the definition of the error model that we'll be using for displaying the possible errors of every field. Now, let's explore the proposed implementation:

text
/* Detailed source-code truncated for AI context efficiency. */

The logic of the validation process is as follows: check every individual field based on the established rules for each one of them. If the validation is successful, then return the field wrapped in a Right instance; If not, then return a DomainValidation with the respective message, wrapped in a Left instance.
Note that we took advantage of the .cond method of Either, that is equivalent to do if (cond) Right(value) else Left(error).

Our service has the validateForm method for checking all the fields and, if the process succeeds it will create an instance of RegistrationData, right?

Well, yes, but the error reporting part will have the downside of showing only the first error.

Let's look this in detail:

scala mdoc:silent:fail
for {
  validatedUserName <- validateUserName(username)
  validatedPassword <- validatePassword(password)
  validatedFirstName <- validateFirstName(firstName)
  validatedLastName <- validateLastName(lastName)
  validatedAge <- validateAge(age)
} yield RegistrationData(validatedUserName, validatedPassword, validatedFirstName, validatedLastName, validatedAge)

A for-comprehension is fail-fast. If some of the evaluations in the for block fails for some reason, the yield statement will not complete. In our case, if that happens we won't be getting the accumulated list of errors.

If we run our code:

scala mdoc
FormValidator.validateForm(
  username = "fakeUs3rname",
  password = "password",
  firstName = "John",
  lastName = "Doe",
  age = 15
)

We should have gotten another DomainValidation object denoting the invalid age.

An iteration with `Validated`

Time to do some refactoring! We're going to try a Validated approach:

scala mdoc:silent
import cats.data._
import cats.data.Validated._
import cats.syntax.all._

def validateUserName(userName: String): Validated[DomainValidation, String] = FormValidator.validateUserName(userName).toValidated

def validatePassword(password: String): Validated[DomainValidation, String] = FormValidator.validatePassword(password).toValidated

def validateFirstName(firstName: String): Validated[DomainValidation, String] = FormValidator.validateFirstName(firstName).toValidated

def validateLastName(lastName: String): Validated[DomainValidation, String] = FormValidator.validateLastName(lastName).toValidated

def validateAge(age: Int): Validated[DomainValidation, Int] = FormValidator.validateAge(age).toValidated
scala mdoc:fail
def validateForm(username: String, password: String, firstName: String, lastName: String, age: Int): Validated[DomainValidation, RegistrationData] = {
  for {
    validatedUserName <- validateUserName(username)
    validatedPassword <- validatePassword(password)
    validatedFirstName <- validateFirstName(firstName)
    validatedLastName <- validateLastName(lastName)
    validatedAge <- validateAge(age)
  } yield RegistrationData(validatedUserName, validatedPassword, validatedFirstName, validatedLastName, validatedAge)
}

What we've done here was to reuse the previously created validation functions and convert their output to a Validated instance with the .toValidated combinator. This one takes an Either and converts it to its equivalent Validated.
This datatype, as with Either has two projections: Valid and Invalid, analogous to Right and Left, respectively.

Remember that our goal is to get all the validation errors for displaying it to the user, but you'll find that this approach won't compile, as you can see in the previous snippet. Why?

Without diving into details about monads, a for-comprehension uses the flatMap method for composition. Monads like Either can be composed in that way, but the thing with Validated is that it isn't a monad, but an Applicative Functor.
That's why you see the message: error: value flatMap is not a member of cats.data.Validated[DomainValidation,String].

So, how do we do here?

Meeting applicative

We have to look into another direction: a for-comprehension plays well in a fail-fast scenario, but the structure in our previous example was designed to catch one error at a time, so, our next step is to tweak the implementation a bit.

scala mdoc:silent
sealed trait FormValidatorNec {

  type ValidationResult[A] = ValidatedNec[DomainValidation, A]

  private def validateUserName(userName: String): ValidationResult[String] =
    if (userName.matches("^[a-zA-Z0-9]+$")) userName.validNec else UsernameHasSpecialCharacters.invalidNec

  private def validatePassword(password: String): ValidationResult[String] =
    if (password.matches("(?=^.{10,}$)((?=.*\\d)|(?=.*\\W+))(?![.\\n])(?=.*[A-Z])(?=.*[a-z]).*$")) password.validNec
    else PasswordDoesNotMeetCriteria.invalidNec

  private def validateFirstName(firstName: String): ValidationResult[String] =
    if (firstName.matches("^[a-zA-Z]+$")) firstName.validNec else FirstNameHasSpecialCharacters.invalidNec

  private def validateLastName(lastName: String): ValidationResult[String] =
    if (lastName.matches("^[a-zA-Z]+$")) lastName.validNec else LastNameHasSpecialCharacters.invalidNec

  private def validateAge(age: Int): ValidationResult[Int] =
    if (age >= 18 && age <= 75) age.validNec else AgeIsInvalid.invalidNec

  def validateForm(username: String, password: String, firstName: String, lastName: String, age: Int): ValidationResult[RegistrationData] = {
    (validateUserName(username),
    validatePassword(password),
    validateFirstName(firstName),
    validateLastName(lastName),
    validateAge(age)).mapN(RegistrationData)
  }

}

object FormValidatorNec extends FormValidatorNec

Let's see what changed here:

  1. In this new implementation, we're using a NonEmptyChain, a data structure that guarantees that at least one element will be present. In case that multiple errors arise, you'll get a chain of DomainValidation.
  2. ValidatedNec[DomainValidation, A] is an alias for Validated[NonEmptyChain[DomainValidation], A]. When you use ValidatedNec you're stating that your accumulative structure will be a NonEmptyChain. With Validated, you have the choice about which data structure you want for reporting the errors (more on that soon).
  3. We've declared the type alias ValidationResult that conveniently expresses the return type of our validation.
  4. .validNec and .invalidNec combinators lets you lift the success or failure in their respective container (either a Valid or Invalid[NonEmptyChain[A]]).
  5. The applicative syntax (a, b, c, ...).mapN(...) provides us a way to accumulatively apply the validation functions and yield a product with their successful result or the accumulated errors in the NonEmptyChain. Then, we transform that product with mapN into a valid instance of RegistrationData.

Deprecation notice: since Cats 1.0.0-MF the cartesian syntax |@| for applicatives is deprecated. If you're using 0.9.0 or less, you can use the syntax: (a |@| b |@| ...).map(...).

Note that, at the end, we expect to lift the result of the validation functions in a RegistrationData instance. If the process fails, we'll get our NonEmptyChain detailing what went wrong.

For example:

scala mdoc
FormValidatorNec.validateForm(
  username = "Joe",
  password = "Passw0r$1234",
  firstName = "John",
  lastName = "Doe",
  age = 21
)

FormValidatorNec.validateForm(
  username = "Joe%%%",
  password = "password",
  firstName = "John",
  lastName = "Doe",
  age = 21
)

Sweet success! Now you can take your validation process to the next level!

A short detour

As previously stated, ValidatedNec[DomainValidation, A] is an alias for Validated[NonEmptyChain[DomainValidation], A]. Typically, you'll see that Validated is accompanied by a NonEmptyChain when it comes to accumulation. The thing here is that you can define your own accumulative data structure and you're not limited to the aforementioned construction.

For doing this, you have to provide a Semigroup instance. NonEmptyChain, by definition has its own Semigroup. For those who don't know what a Semigroup is, you can find out more here.

Accumulative Structures

Let's take a look about how a Semigroup works in a NonEmptyChain:

scala mdoc
NonEmptyChain.one[DomainValidation](UsernameHasSpecialCharacters) |+| NonEmptyChain[DomainValidation](FirstNameHasSpecialCharacters, LastNameHasSpecialCharacters)

We're combining a couple of NonEmptyChains. The first one has its mandatory element (note that we've built an instance of it with .one) and the second has a couple of elements. As you can see, the output of the combination, expressed by the |+| operator is another NonEmptyChain with the three elements.

But, what about if we want another way of combining? We can provide our custom Semigroup instance with the desired combining logic and pass it implicitly to your scope.

Going back and forth

Cats offers you a nice set of combinators for transforming your Validated based approach to an Either one and vice-versa.
We've used .toValidated in our second example, now let's see how to use .toEither.

From `Validated` to `Either`

To do this, simply use .toEither combinator:

scala mdoc
// Successful case
FormValidatorNec.validateForm(
  username = "Joe",
  password = "Passw0r$1234",
  firstName = "John",
  lastName = "Doe",
  age = 21
).toEither

// Invalid case
FormValidatorNec.validateForm(
  username = "Joe123#",
  password = "password",
  firstName = "John",
  lastName = "Doe",
  age = 5
).toEither

With this conversion, as you can see, we got an Either with a NonEmptyChain detailing the possible validation errors or our RegistrationData object.

Another case

Perhaps you're reading from a configuration file. One could imagine the configuration library you're using returns
a scala.util.Try, or maybe a scala.util.Either. Your parsing may look something like:

scala
for {
  url  <- config[String]("url")
  port <- config[Int]("port")
} yield ConnectionParams(url, port)

You run your program and it says key "url" not found, turns out the key was "endpoint". So you change your code
and re-run. Now it says the "port" key was not a well-formed integer.

Parallel validation

Our goal is to report any and all errors across independent bits of data. For instance, when we ask for several
pieces of configuration, each configuration field can be validated separately from one another. How then do we
enforce that the data we are working with is independent? We ask for both of them up front.

As our running example, we will look at config parsing. Our config will be represented by a
Map[String, String]. Parsing will be handled by a Read type class - we provide instances
just for String and Int for brevity.

scala mdoc:silent:reset
trait Read[A] {
  def read(s: String): Option[A]
}

object Read {
  def apply[A](implicit A: Read[A]): Read[A] = A

  implicit val stringRead: Read[String] =
    new Read[String] { def read(s: String): Option[String] = Some(s) }

  implicit val intRead: Read[Int] =
    new Read[Int] {
      def read(s: String): Option[Int] =
        if (s.matches("-?[0-9]+")) Some(s.toInt)
        else None
    }
}

Then we enumerate our errors - when asking for a config value, one of two things can
go wrong: the field is missing, or it is not well-formed with regards to the expected
type.

scala mdoc:silent
sealed abstract class ConfigError
final case class MissingConfig(field: String) extends ConfigError
final case class ParseError(field: String) extends ConfigError

We need a data type that can represent either a successful value (a parsed configuration),
or an error.

scala
sealed abstract class Validated[+E, +A]

object Validated {
  final case class Valid[+A](a: A) extends Validated[Nothing, A]
  final case class Invalid[+E](e: E) extends Validated[E, Nothing]
}

Now we are ready to write our parser.

scala mdoc:silent
import cats.data.Validated
import cats.data.Validated.{Invalid, Valid}

case class Config(map: Map[String, String]) {
  def parse[A : Read](key: String): Validated[ConfigError, A] =
    map.get(key) match {
      case None        => Invalid(MissingConfig(key))
      case Some(value) =>
        Read[A].read(value) match {
          case None    => Invalid(ParseError(key))
          case Some(a) => Valid(a)
        }
    }
}

Everything is in place to write the parallel validator. Recall that we can only do parallel
validation if each piece is independent. How do we enforce the data is independent? By asking
for all of it up front. Let's start with two pieces of data.

scala mdoc:silent
def parallelValidateSimple[E, A, B, C](v1: Validated[E, A], v2: Validated[E, B])(f: (A, B) => C): Validated[E, C] =
  (v1, v2) match {
    case (Valid(a), Valid(b))       => Valid(f(a, b))
    case (Valid(_), i@Invalid(_))   => i
    case (i@Invalid(_), Valid(_))   => i
    case (Invalid(e1), Invalid(e2)) => ???
  }

We've run into a problem. In the case where both have errors, we want to report both. But we have
no way of combining the two errors into one error! Perhaps we can put both errors into a Chain,
but that seems needlessly specific - clients may want to define their own way of combining errors.

How then do we abstract over a binary operation? The Semigroup type class captures this idea.

scala mdoc:silent
import cats.Semigroup

def parallelValidate[E : Semigroup, A, B, C](v1: Validated[E, A], v2: Validated[E, B])(f: (A, B) => C): Validated[E, C] =
  (v1, v2) match {
    case (Valid(a), Valid(b))       => Valid(f(a, b))
    case (Valid(_), i@Invalid(_))   => i
    case (i@Invalid(_), Valid(_))   => i
    case (Invalid(e1), Invalid(e2)) => Invalid(Semigroup[E].combine(e1, e2))
  }

Perfect! But.. going back to our example, we don't have a way to combine ConfigErrors. But as clients,
we can change our Validated values where the error can be combined, say, a Chain[ConfigError]. It is
more common however to use a NonEmptyChain[ConfigError] - the NonEmptyChain statically guarantees we
have at least one value, which aligns with the fact that if we have an Invalid, then we most
certainly have at least one error. This technique is so common there is a convenient method on Validated
called toValidatedNec that turns any Validated[E, A] value to a Validated[NonEmptyChain[E], A].
Additionally, the type alias ValidatedNec[E, A] is provided.

Time to parse.

scala mdoc:silent:nest
import cats.SemigroupK
import cats.data.NonEmptyChain
import cats.syntax.all._

case class ConnectionParams(url: String, port: Int)

val config = Config(Map(("endpoint", "127.0.0.1"), ("port", "not an int")))

implicit val necSemigroup: Semigroup[NonEmptyChain[ConfigError]] =
  SemigroupK[NonEmptyChain].algebra[ConfigError]

implicit val readString: Read[String] = Read.stringRead
implicit val readInt: Read[Int] = Read.intRead

Any and all errors are reported!

scala mdoc:nest
val v1 = parallelValidate(config.parse[String]("url").toValidatedNec,
                          config.parse[Int]("port").toValidatedNec)(ConnectionParams.apply)

val v2 = parallelValidate(config.parse[String]("endpoint").toValidatedNec,
                          config.parse[Int]("port").toValidatedNec)(ConnectionParams.apply)
scala mdoc:nest
val config = Config(Map(("endpoint", "127.0.0.1"), ("port", "1234")))
val v3 = parallelValidate(config.parse[String]("endpoint").toValidatedNec,
                          config.parse[Int]("port").toValidatedNec)(ConnectionParams.apply)

Apply

Our parallelValidate function looks awfully like the Apply#map2 function.

scala
def map2[F[_], A, B, C](fa: F[A], fb: F[B])(f: (A, B) => C): F[C]

Which can be defined in terms of Apply#ap and Apply#map, the very functions needed to create an Apply instance.

Can we perhaps define an Apply instance for Validated? Better yet, can we define an Applicative instance?

Note: the example below assumes usage of the kind-projector compiler plugin and will not compile if it is not being used in a project.

scala mdoc:silent
import cats.Applicative

implicit def validatedApplicative[E : Semigroup]: Applicative[Validated[E, *]] =
  new Applicative[Validated[E, *]] {
    def ap[A, B](f: Validated[E, A => B])(fa: Validated[E, A]): Validated[E, B] =
      (fa, f) match {
        case (Valid(a), Valid(fab)) => Valid(fab(a))
        case (i@Invalid(_), Valid(_)) => i
        case (Valid(_), i@Invalid(_)) => i
        case (Invalid(e1), Invalid(e2)) => Invalid(Semigroup[E].combine(e1, e2))
      }

    def pure[A](x: A): Validated[E, A] = Validated.valid(x)
  }

Awesome! And now we also get access to all the goodness of Applicative, which includes map{2-22}, as well as the
Semigroupal tuple syntax.

We can now easily ask for several bits of configuration and get any and all errors returned back.

scala mdoc:silent:nest
import cats.Apply
import cats.data.ValidatedNec

implicit def necSemigroup: Semigroup[NonEmptyChain[ConfigError]] =
  SemigroupK[NonEmptyChain].algebra[ConfigError]

val personConfig = Config(Map(("name", "cat"), ("age", "not a number"), ("houseNumber", "1234"), ("lane", "feline street")))

case class Address(houseNumber: Int, street: String)
case class Person(name: String, age: Int, address: Address)

val personFromConfig: ValidatedNec[ConfigError, Person] =
  Apply[ValidatedNec[ConfigError, *]].map4(personConfig.parse[String]("name").toValidatedNec,
                                           personConfig.parse[Int]("age").toValidatedNec,
                                           personConfig.parse[Int]("house_number").toValidatedNec,
                                           personConfig.parse[String]("street").toValidatedNec) {
    case (name, age, houseNumber, street) => Person(name, age, Address(houseNumber, street))
  }

Of `flatMap`s and `Either`s

Option has flatMap, Either has flatMap, where's Validated's? Let's try to implement it - better yet,
let's implement the Monad type class.

scala mdoc:silent:nest
import cats.Monad

implicit def validatedMonad[E]: Monad[Validated[E, *]] =
  new Monad[Validated[E, *]] {
    def flatMap[A, B](fa: Validated[E, A])(f: A => Validated[E, B]): Validated[E, B] =
      fa match {
        case Valid(a)     => f(a)
        case i@Invalid(_) => i
      }

    def pure[A](x: A): Validated[E, A] = Valid(x)

    @annotation.tailrec
    def tailRecM[A, B](a: A)(f: A => Validated[E, Either[A, B]]): Validated[E, B] =
      f(a) match {
        case Valid(Right(b)) => Valid(b)
        case Valid(Left(a)) => tailRecM(a)(f)
        case i@Invalid(_) => i
      }
  }

Note that all Monad instances are also Applicative instances, where ap is defined as

scala mdoc:compile-only
trait Monad[F[_]] {
  def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
  def pure[A](x: A): F[A]

  def map[A, B](fa: F[A])(f: A => B): F[B] =
    flatMap(fa)(f.andThen(pure))

  def ap[A, B](fa: F[A])(f: F[A => B]): F[B] =
    flatMap(fa)(a => map(f)(fab => fab(a)))
}

However, the ap behavior defined in terms of flatMap does not behave the same as that of
our ap defined above. Observe:

scala mdoc
validatedMonad.tuple2(Validated.invalidNec[String, Int]("oops"), Validated.invalidNec[String, Double]("uh oh"))

This one short circuits! Therefore, if we were to define a Monad (or FlatMap) instance for Validated we would
have to override ap to get the behavior we want.

scala mdoc:silent:nest
import cats.Monad

implicit def accumulatingValidatedMonad[E: Semigroup]: Monad[Validated[E, *]] =
  new Monad[Validated[E, *]] {
    def flatMap[A, B](fa: Validated[E, A])(f: A => Validated[E, B]): Validated[E, B] =
      fa match {
        case Valid(a)     => f(a)
        case i@Invalid(_) => i
      }

    def pure[A](x: A): Validated[E, A] = Valid(x)

    @annotation.tailrec
    def tailRecM[A, B](a: A)(f: A => Validated[E, Either[A, B]]): Validated[E, B] =
      f(a) match {
        case Valid(Right(b)) => Valid(b)
        case Valid(Left(a)) => tailRecM(a)(f)
        case i@Invalid(_) => i
      }

    override def ap[A, B](f: Validated[E, A => B])(fa: Validated[E, A]): Validated[E, B] =
      (fa, f) match {
        case (Valid(a), Valid(fab)) => Valid(fab(a))
        case (i@Invalid(_), Valid(_)) => i
        case (Valid(_), i@Invalid(_)) => i
        case (Invalid(e1), Invalid(e2)) => Invalid(Semigroup[E].combine(e1, e2))
      }
  }

But then the behavior of flatMap would be inconsistent with that of ap, and this will violate one of the FlatMap laws, flatMapConsistentApply:

scala
// the `<->` operator means "is equivalent to" and returns a data structure
// `IsEq` that is used to verify the equivalence of the two expressions
def flatMapConsistentApply[A, B](fa: F[A], fab: F[A => B]): IsEq[F[B]] = 
  fab.ap(fa) <-> fab.flatMap(f => fa.map(f))
scala mdoc:silent
import cats.laws._

val flatMapLawsForAccumulatingValidatedMonad = 
  FlatMapLaws[Validated[NonEmptyChain[String], *]](accumulatingValidatedMonad)

val fa  = Validated.invalidNec[String, Int]("oops")
val fab = Validated.invalidNec[String, Int => Double]("Broken function")
scala mdoc
flatMapLawsForAccumulatingValidatedMonad.flatMapConsistentApply(fa , fab)

Therefore, Validated has only an Applicative instance.

`Validated` vs `Either`

We've established that an error-accumulating data type such as Validated can't have a valid Monad instance. Sometimes the task at hand requires error-accumulation. However, sometimes we want a monadic structure that we can use for sequential validation (such as in a for-comprehension). This leaves us in a bit of a conundrum.

Cats has decided to solve this problem by using separate data structures for error-accumulation (Validated) and short-circuiting monadic behavior (Either).

If you are trying to decide whether you want to use Validated or Either, a simple heuristic is to use Validated if you want error-accumulation and to otherwise use Either.

Sequential Validation

If you do want error accumulation but occasionally run into places where you sequential validation is needed, then Validated provides a couple methods that may be helpful.

`andThen`

The andThen method is similar to flatMap (such as Either.flatMap). In the case of success, it passes the valid value into a function that returns a new Validated instance.

scala mdoc
val houseNumber = config.parse[Int]("house_number").andThen{ n =>
   if (n >= 0) Validated.valid(n)
   else Validated.invalid(ParseError("house_number"))
}

`withEither`

The withEither method allows you to temporarily turn a Validated instance into an Either instance and apply it to a function.

scala mdoc:silent
def positive(field: String, i: Int): Either[ConfigError, Int] = {
  if (i >= 0) Right(i)
  else Left(ParseError(field))
}

Thus.

scala mdoc:nest
val houseNumber = config.parse[Int]("house_number").withEither{ either: Either[ConfigError, Int] =>
  either.flatMap{ i =>
    positive("house_number", i)
  }
}

Datatypes Writer (`docs/datatypes/writer.md`)

Writer

API Documentation: @:api(cats.data.WriterT)

The Writer[L, A] datatype represents a computation that produces a
tuple containing a value of type L and one of type A. Usually, the
value L represents a description of the computation. A typical
example of an L value could be a logging String and that's why
from now on we will refer to it as the Logging side of the
datatype. Meanwhile, the value A is the actual output of the
computation.

The main features that Writer provides are:

The flexibility regarding Log value management. It can be modified in
multiple ways. See the Operations section

When two functions are composed together, e.g. using flatMap, the logs
of both functions will be combined using an implicit
Semigroup.

Operations

The Writer datatype provides a set of functions that are similar to
the ones from the
Monad
typeclass. In fact, they share the same name and the same signature,
but have an additional requirement of a
Semigroup[L]
that allows the log merging.

map effects only the value, keeping the log side untouched. Plus, here we show run
that just unwrap the datatype, returning its content.

scala mdoc
import cats.data.Writer
import cats.instances._

val mapExample = Writer("map Example", 1).map(_ + 1)

mapExample.run

ap allows applying a function, wrapped into a Writer. It works
exactly like the Applicative as expected, but notice how the logs
are combined using the Semigroup[String].

scala mdoc
val apExampleValue = Writer("ap value", 10)
val apExampleFunc = Writer("ap function ", (i: Int) => i % 7)

apExampleValue.ap(apExampleFunc).run

Same thing for flatMap

scala mdoc
val flatMapExample1 = Writer("flatmap value", 5)
val flatMapExample2 = (x: Int) => Writer("flatmap function ", x * x)

flatMapExample1.flatMap(flatMapExample2).run

// We can use the for comprehension as well
val flatMapForResult = for {
    value <- Writer("flatmap value", 5)
    result <- flatMapExample2(value)
} yield result

flatMapForResult.run

Apart from those, Writer comes with some specific functions to manage
the log side of the computation:

tell
: Append a value to the log side. It requires a Semigroup[L].

swap
: Exchange the two values of the Writer.

reset
: Delete the log side. It requires a Monoid[L] since it uses the empty value of the monoid.

value
: Returns only the value of the Writer

listen
: Transform the value of the Writer to a tuple containing the
current value and the current log.

scala mdoc
val tellExample = Writer("tell example", 1).tell("log append")

tellExample.run

val swapExample = Writer("new value", "new log").swap

swapExample.run

val resetExample = Writer("long log to discard", 42).reset

resetExample.run

val valueExample = Writer("some log", 55).value

valueExample

val listenExample = Writer("listen log", 10).listen

listenExample.run

Definition

If we go looking at how Writer is actually defined, we will see
it is just a type alias:

scala mdoc:silent
import cats.data.WriterT
import cats.Id
// cats/data/package.scala
type Writer[L, V] = WriterT[Id, L, V]

So, all the Operations defined in the previous section
are actually coming from the WriterT
datatype

Most of the WriterT functions require a
Functor[F] or
Monad[F]
instance. However, Cats provides all the necessary instances for the
Id type, therefore
we don't have to worry about them.

Example

The example showed in here is taken from the Rosetta Code
site
. It simply
applies a bunch of Math operations, logging each one of them.

scala mdoc:silent:reset
import cats.data.Writer
import scala.math.sqrt

val writer1: Writer[String, Double] = Writer.value[String, Double](5.0).tell("Initial value ")
val writer2: Writer[String, Double => Double] = Writer("sqrt ", (i: Double) => sqrt(i))
val writer3: Double => Writer[String, Double] = (x: Double) => Writer("add 1 ", x + 1)
val writer4: Writer[String, Double => Double] = Writer("divided by 2 ", (x: Double) => x / 2)

val writer5: Writer[String, Double => Double] = Writer[String, Double => Double](writer3(0).written,(x: Double) => writer3(x).value)
scala mdoc
// Pay attention on the ordering of the logs

writer1
  .ap(writer2)
  .flatMap(writer3(_))
  .ap(writer4)
  .map(_.toString)
  .run

import cats.syntax.compose._

(for {
    initialValue <- writer1
    sqrt <- writer2
    addOne <- writer5
    divideBy2 <- writer4
    } yield (sqrt >>> addOne >>> divideBy2)(initialValue)
).run

If you are interested in logging solutions, we recommend the library log4cats


Datatypes Writert (`docs/datatypes/writert.md`)

WriterT

API Documentation: @:api(cats.data.WriterT)

WriterT[F[_], L, V] is a type wrapper on an F[(L, V)]. Speaking technically, it is a monad transformer for Writer,
but you don't need to know what that means for it to be
useful.

Composition

WriterT can be more convenient to work with than using
F[Writer[L, V]] directly, because it exposes operations that allow
you to work with the values of the inner Writer (L and
V) abstracting both the F and Writer.

For example, map allow you to transform the inner V value, getting
back a WriterT that wraps around it.

scala mdoc:nest
import cats.data.{WriterT, Writer}

WriterT[Option, String, Int](Some(("value", 10))).map(x => x * x)

Plus, when composing multiple WriterT computations, those will be
composed following the same behaviour of a
Writer and the
generic F. Let's see two examples with Option and Either: if
one of the computations has a None or a Left, the whole
computation will return a None or a Left since the way the two
types compose typically behaves that way. Moreover, when the
computation succeed, the logging side of the
Writers will be
combined.

scala mdoc:silent
val optionWriterT1 : WriterT[Option, String, Int] = WriterT(Some(("writerT value 1", 123)))
val optionWriterT2 : WriterT[Option, String, Int] = WriterT(Some(("writerT value 1", 123)))
val optionWriterT3 : WriterT[Option, String, Int] = WriterT.valueT(None)


val eitherWriterT1 : WriterT[Either[String, *], String, Int] = WriterT(Right(("writerT value 1", 123)))
val eitherWriterT2 : WriterT[Either[String, *], String, Int] = WriterT(Right(("writerT value 1", 123)))
val eitherWriterT3 : WriterT[Either[String, *], String, Int] = WriterT.valueT(Left("error!!!"))
scala mdoc
// This returns a Some since both are Some
for {
    v1 <- optionWriterT1
    v2 <- optionWriterT2
} yield v1 + v2

// This returns a None since one is a None
for {
    v1 <- optionWriterT1
    v2 <- optionWriterT2
    v3 <- optionWriterT3
} yield v1 + v2 + v3

// This returns a Right since both are Right
for {
    v1 <- eitherWriterT1
    v2 <- eitherWriterT2
} yield v1 + v2

// This returns a Left since one is a Left
for {
    v1 <- eitherWriterT1
    v2 <- eitherWriterT2
    v3 <- eitherWriterT3
} yield v1 + v2 + v3

Just for completeness, we can have a look at the same example, but
with
Validated
since it as a slightly different behaviour than
Either. Instead
of short-circuiting when the first error is encountered,
Validated
will accumulate all the errors. In the following example, you can see
how this behaviour is respected when
Validated is
wrapped as the F type of a WriterT. In addition, notice
how flatMap and for comprehension can't be used in this case, since
Validated
only extends Applicative, but not Monad.

scala mdoc:silent
import cats.data.Validated
import cats.data.Validated.{Invalid, Valid}
import cats.syntax.all._

val validatedWriterT1 : WriterT[Validated[String, *], String, Int] = WriterT(Valid(("writerT value 1", 123)))
val validatedWriterT2 : WriterT[Validated[String, *], String, Int] = WriterT(Valid(("writerT value 1", 123)))
val validatedWriterT3 : WriterT[Validated[String, *], String, Int] =
WriterT(Invalid("error 1!!!") : Validated[String, (String, Int)])
val validatedWriterT4 : WriterT[Validated[String, *], String, Int] = WriterT(Invalid("error 2!!!"): Validated[String, (String, Int)])
scala mdoc
// This returns a Right since both are Right
(validatedWriterT1,
validatedWriterT2
).mapN((v1, v2) => v1 + v2)

// This returns a Left since there are several Left
(validatedWriterT1,
 validatedWriterT2,
 validatedWriterT3,
 validatedWriterT4
).mapN((v1, v2, v3, v4) => v1 + v2 + v3 + v4)

Construct a WriterT

A WriterT can be constructed in different ways. Here is the
list of the main available constructors with a brief explanation and
an example.

WriterT[F[_], L, V](run: F[(L, V)])
: This is the constructor of the datatype itself. It just builds the
type starting from the full wrapped value.

scala mdoc:nest
// Here we use Option as our F[_]
  val value : Option[(String, Int)] = Some(("value", 123))
  WriterT(value)

liftF[F[_], L, V](fv: F[V])(implicit monoidL: Monoid[L], F: Applicative[F]): WriterT[F, L, V]
: This function allows you to build the datatype starting from the
value V wrapped into an F. Notice how it requires:

  • Monoid[L], since it uses the empty value from the typeclass.
    to fill the L value not specified in the input.
  • Applicative[F] to modify the inner value.
scala mdoc:nest
import cats.instances.option._

  val value : Option[Int] = Some(123)

  WriterT.liftF[Option, String, Int](value)

put[F[_], L, V](v: V)(l: L)(implicit applicativeF: Applicative[F]): WriterT[F, L, V]
: As soon as there is an Applicative instance of F, this function
creates the datatype starting from the inner Writer's values.

scala mdoc:nest
WriterT.put[Option, String, Int](123)("initial value")

putT[F[_], L, V](vf: F[V])(l: L)(implicit functorF: Functor[F]): WriterT[F, L, V]
: Exactly as put, but the value V is already wrapped into F

scala mdoc:nest
WriterT.putT[Option, String, Int](Some(123))("initial value")

Operations

In the Writer
definition

section, we showed how it is actually a WriterT. Therefore, all the
operations described into Writer
operations

are valid for WriterT as well.

The only aspect we want to remark here is the following sentence from
Writer's page:

Most of the WriterT functions require a Functor[F] or
Monad[F] instance. However, Cats provides all the necessary
instances for the Id type, therefore we don't have to worry about
them.

In the case of WriterT, the user needs to ensure the required
instances are present. Cats still provide a lot of default instances,
so there's a high chance you could find what you are searching for
with the right import.

Example

As an example, we can consider a simple naive console application that
pings multiple HTTP well-known services and collect the time
spent in each call, returning the total time of the whole execution at
the end. We will simulate the calls by successful Future values.

Using WriterT we can log each step of our application,
compute, the time and work within the Future effect.

scala mdoc:silent
import cats.data.WriterT

import scala.concurrent.{Await, Future}
import scala.concurrent.duration.Duration
import scala.concurrent.ExecutionContext.Implicits.global

// Mocked HTTP calls
def pingService1() : Future[Int] = Future.successful(100)
def pingService2() : Future[Int] = Future.successful(200)
def pingService3() : Future[Int] = Future.successful(50)
def pingService4() : Future[Int] = Future.successful(75)

def pingToWriterT(ping: Future[Int], serviceName: String) : WriterT[Future, String, Int] =
    WriterT.valueT[Future, String, Int](ping)
        .tell(s"ping to $serviceName ")
        .flatMap(pingTime => WriterT.put(pingTime)(s"took $pingTime \n"))

val resultWriterT: WriterT[Future, String, Int] = for {
    ping1 <- pingToWriterT(pingService1(), "service #1")
    ping2 <- pingToWriterT(pingService2(), "service #2")
    ping3 <- pingToWriterT(pingService3(), "service #3")
    ping4 <- pingToWriterT(pingService4(), "service #4")
  } yield ping1 + ping2 + ping3 + ping4

val resultFuture: Future[String] = resultWriterT.run.map {
    case (log: String, totalTime: Int) => s"$log> Total time: $totalTime"
}

And the final result as expected:

scala mdoc
Await.result(resultFuture, Duration.Inf)

Typeclasses Alternative (`docs/typeclasses/alternative.md`)

Alternative

API Documentation: @:api(cats.Alternative)

Alternative extends Applicative with a MonoidK.
Let's stub out all the operations just to remind ourselves what that gets us.

scala mdoc:silent
import cats.{Applicative, MonoidK}

trait Alternative[F[_]] extends Applicative[F] with MonoidK[F] {
  def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]

  def pure[A](a: A): F[A]

  def empty[A]: F[A]

  def combineK[A](x: F[A], y: F[A]): F[A]
}

As you might recall, pure wraps values in the context; ap allows us to do calculations in the context; combineK allows us to combine, for any given type A, any two contextual values F[A]; and empty provides the identity element for the combine operation.

Like other type classes, Alternative instances must obey some laws, in addition to those otherwise applying to MonoidK and Applicative instances:

  • Right Absorption: Applying a contextual function F[A => B] to empty [A] should be empty [B].

    • ff ap F.empty[A] = F.empty[B].
  • Left Distributivity: Mapping over a combined element must be the combinations of the mapped elements.

    • (fa <+> fb) map f = ((fa map f) <+> (fb map f)) where fa: F[A] and fb: F[B] and f: A => B.
  • Right Distributivity: Applying the combination of two functions must be the combination of their applications.

    • (ff <+> fg) ap fa = (ff ap fa) <+> (fg ap fa) where ff: F[A => B], fg: F[A => B], and fa: F[A].

These laws guarantee the compatibility of the otherwise possibly independent Applicative and MonoidK structures.

Vector as an Alternative

Let's examine an instance to get a feel for things. A useful instance of Alternative is that for Vector.

The relevant imports:

scala mdoc:reset:silent
import cats.Alternative
import cats.syntax.all._

And what we can do with them:

scala mdoc
val empty = Alternative[Vector].empty[Int]
val pureOfFive = 5.pure[Vector]
val concatenated = 7.pure[Vector] <+> 8.pure[Vector]
val double: Int => Int = _ * 2
val addFive: Int => Int = _ + 5
val apForVectors = (double.pure[Vector] <+> addFive.pure[Vector]) ap concatenated

Making choices with `Alternative`

Alternative Parsing

Suppose we have a simple parser library with an interface something like:

scala mdoc:silent
trait Decoder[A] {
  def decode(in: String): Either[Throwable, A]
}
object Decoder {
  def from[A](f: String => Either[Throwable, A]): Decoder[A] =
    new Decoder[A] {
      def decode(in: String) = f(in)
    }
}

Then, we can implement an Alternative instance for this type like so:

scala mdoc:silent
implicit val decoderAlternative: Alternative[Decoder] = new Alternative[Decoder] {
  def pure[A](a: A) = Decoder.from(Function.const(Right(a)))

  def empty[A] = Decoder.from(Function.const(Left(new Error("No dice."))))

  def combineK[A](l: Decoder[A], r: Decoder[A]): Decoder[A] =
    new Decoder[A] {
      def decode(in: String) = l.decode(in).orElse(r.decode(in))
    }

  def ap[A, B](ff: Decoder[A => B])(fa: Decoder[A]): Decoder[B] =
    new Decoder[B] {
      def decode(in: String) = fa.decode(in) ap ff.decode(in)
    }
}

The addition of the Alternative methods allows us to prioritize multiple strategies, compensating for inconsistencies in the source data.

scala mdoc:silent
def parseInt(s: String): Either[Throwable, Int] = Either.catchNonFatal(s.toInt)
def parseIntFirstChar(s: String): Either[Throwable, Int] = Either.catchNonFatal(2 * Character.digit(s.charAt(0), 10))

// Try first parsing the whole, then just the first character.
val decoder: Decoder[Int] = Decoder.from(parseInt _) <+> Decoder.from(parseIntFirstChar _)

This decoder correctly attempts each strategy in turn, as you can see:

scala mdoc
decoder.decode("555")
decoder.decode("5a")

Partitioning Results

Alternative gives us a notion of partitioning, as long as we also have a Monad available. This is what separate does.

The trick here is that the inner type constructor (essentially the replacement for Boolean as the target of our "predicate") must have a Bifoldable available. A great example of a Bifoldable is Either, and another is Tuple2.

Let's imagine that we're trying to make a bunch of independent possibly failure-prone calls with a bunch of different Int inputs (say it's the id of a resource), each returning Either[String, Int] where a left String is the code modeling the failure we're given (say it's the HTTP code returned by a remote API we're calling), while right of an integer is the output of the calculation.

scala mdoc:silent
// Resource holder returns (Request, Status)
def requestResource(a: Int): Either[(Int, String), (Int, Long)] = {
  if (a % 4 == 0) Left((a, "Bad request"))
  else if (a % 3 == 0) Left((a, "Server error"))
  else Right((a, 200L))
}

We can use separate to pull apart the failures and successes zipped with the input, letting us log failures and proceed with successes intelligently. separate will pull the two different outcomes into different sides of a tuple.

scala mdoc
val partitionedResults = 
  ((requestResource _).pure[Vector] ap Vector(5, 6, 7, 99, 1200, 8, 22)).separate

Alternatively (no pun intended), in a totally different version of the same idea, we can lean on the instance of Bitraverse for Tuple2 to try and partition cleanly the outcomes of two different calculations that each depend pairwise on the same input (maybe we have a primary key and we want to select both the remote id of the resources with that key, and those that are linked via the foreign key to the input key).

scala mdoc
// Surprising regularity in this politico-geographical data model!
def getRegionAndDistrict(pkey: Int): (Int, Vector[Int]) = (5 * pkey, (double.pure[Vector] <+> addFive.pure[Vector]) ap pkey.pure[Vector])

val regionsWithDistricts = (getRegionAndDistrict _).pure[Vector] ap Vector(5, 6, 7, 97, 1200, 8, 25)
val regionIds = regionsWithDistricts.separate._1
val districtIds = regionsWithDistricts.separate._2.flatten

Typeclasses Applicative (`docs/typeclasses/applicative.md`)

Applicative

API Documentation: @:api(cats.Applicative)

Applicative extends Functor with an ap and pure method.

scala mdoc:silent
import cats.Functor

trait Applicative[F[_]] extends Functor[F] {
  def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]

  def pure[A](a: A): F[A]

  def map[A, B](fa: F[A])(f: A => B): F[B] = ap(pure(f))(fa)
}

pure wraps the value into the type constructor - for Option this could be Some(_), for Future
Future.successful, and for List a singleton list.

ap is a bit tricky to explain and motivate, so we'll look at an alternative but equivalent
formulation via product.

scala mdoc:silent:nest
trait Applicative[F[_]] extends Functor[F] {
  def product[A, B](fa: F[A], fb: F[B]): F[(A, B)]

  def pure[A](a: A): F[A]
}

// Example implementation for right-biased Either
implicit def applicativeForEither[L]: Applicative[Either[L, *]] = new Applicative[Either[L, *]] {
  def product[A, B](fa: Either[L, A], fb: Either[L, B]): Either[L, (A, B)] = (fa, fb) match {
    case (Right(a), Right(b)) => Right((a, b))
    case (Left(l) , _       ) => Left(l)
    case (_       , Left(l) ) => Left(l)
  }

  def pure[A](a: A): Either[L, A] = Right(a)

  def map[A, B](fa: Either[L, A])(f: A => B): Either[L, B] = fa match {
    case Right(a) => Right(f(a))
    case Left(l)  => Left(l)
  }
}

Note that in this formulation map is left abstract, whereas in the previous one with ap map
could be implemented in terms of ap and pure. This suggests that ap is equivalent to
map and product, which is indeed the case.

Such an Applicative must obey three laws:

  • Associativity: No matter the order in which you product together three values, the result is isomorphic
    • fa.product(fb).product(fc) ~ fa.product(fb.product(fc))
    • With map, this can be made into an equality with fa.product(fb).product(fc) = fa.product(fb.product(fc)).map { case (a, (b, c)) => ((a, b), c) }
  • Left identity: Zipping a value on the left with unit results in something isomorphic to the original value
    • pure(()).product(fa) ~ fa
    • As an equality: pure(()).product(fa).map(_._2) = fa
  • Right identity: Zipping a value on the right with unit results in something isomorphic to the original value
    • fa.product(pure(())) ~ fa
    • As an equality: fa.product(pure(())).map(_._1) = fa

Applicatives for effect management

If we view Functor as the ability to work with a single effect, Applicative encodes working with
multiple independent effects. Between product and map, we can take two separate effectful values
and compose them. From there we can generalize to working with any N number of independent effects.

scala mdoc:reset:silent
import cats.Applicative

def product3[F[_]: Applicative, A, B, C](fa: F[A], fb: F[B], fc: F[C]): F[(A, B, C)] = {
  val F = Applicative[F]
  val fabc = F.product(F.product(fa, fb), fc)
  F.map(fabc) { case ((a, b), c) => (a, b, c) }
}

What is ap?

Let's see what happens if we try to compose two effectful values with just map.

scala mdoc:silent
import cats.syntax.all._

val f: (Int, Char) => Double = (i, c) => (i + c).toDouble

val int: Option[Int] = Some(5)
val char: Option[Char] = Some('a')
scala mdoc
int.map(i => (c: Char) => f(i, c)) // what now?

We have an Option[Char => Double] and an Option[Char] to which we want to apply the function to,
but map doesn't give us enough power to do that. Hence, ap.

Applicatives compose

Like Functor, Applicatives compose. If F and G have Applicative instances, then so
does F[G[_]].

scala mdoc:silent
import cats.data.Nested
import cats.syntax.all._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

val x: Future[Option[Int]] = Future.successful(Some(5))
val y: Future[Option[Char]] = Future.successful(Some('a'))
scala mdoc
val composed = Applicative[Future].compose[Option].map2(x, y)(_ + _)

val nested = Applicative[Nested[Future, Option, *]].map2(Nested(x), Nested(y))(_ + _)

Traverse

The straightforward way to use product and map (or just ap) is to compose n independent effects,
where n is a fixed number. In fact there are convenience methods named apN, mapN, and tupleN (replacing
N with a number 2 - 22) to make it even easier.

Imagine we have one Option representing a username, one representing a password, and another representing
a URL for logging into a database.

scala mdoc:silent
import java.sql.Connection

val username: Option[String] = Some("username")
val password: Option[String] = Some("password")
val url: Option[String] = Some("some.login.url.here")

// Stub for demonstration purposes
def attemptConnect(username: String, password: String, url: String): Option[Connection] = None

We know statically we have 3 Options, so we can use map3 specifically.

scala mdoc
Applicative[Option].map3(username, password, url)(attemptConnect)

Sometimes we don't know how many effects will be in play - perhaps we are receiving a list from user
input or getting rows from a database. This implies the need for a function:

scala mdoc:silent
def sequenceOption[A](fa: List[Option[A]]): Option[List[A]] = ???

// Alternatively..
def traverseOption[A, B](as: List[A])(f: A => Option[B]): Option[List[B]] = ???

Users of the standard library Future.sequence or Future.traverse will find these names and signatures
familiar.

Let's implement traverseOption (you can implement sequenceOption in terms of traverseOption).

scala mdoc:silent:nest
def traverseOption[A, B](as: List[A])(f: A => Option[B]): Option[List[B]] =
  as.foldRight(Some(List.empty[B]): Option[List[B]]) { (a: A, acc: Option[List[B]]) =>
    val optB: Option[B] = f(a)
    // optB and acc are independent effects so we can use Applicative to compose
    Applicative[Option].map2(optB, acc)(_ :: _)
  }

traverseOption(List(1, 2, 3))(i => Some(i): Option[Int])

This works...but if we look carefully at the implementation there's nothing Option-specific going on. As
another example let's implement the same function but for Either.

scala mdoc:silent
import cats.syntax.all._

def traverseEither[E, A, B](as: List[A])(f: A => Either[E, B]): Either[E, List[B]] =
  as.foldRight(Right(List.empty[B]): Either[E, List[B]]) { (a: A, acc: Either[E, List[B]]) =>
    val eitherB: Either[E, B] = f(a)
    Applicative[Either[E, *]].map2(eitherB, acc)(_ :: _)
  }
scala mdoc
traverseEither(List(1, 2, 3))(i => if (i % 2 != 0) Left(s"${i} is not even") else Right(i / 2))

The implementation of traverseOption and traverseEither are more or less identical, modulo the initial
"accumulator" to foldRight. But even that could be made the same by delegating to Applicative#pure!
Generalizing Option and Either to any F[_]: Applicative gives us the fully polymorphic version.
Existing data types with Applicative instances (Future, Option, Either[E, *], Try) can call it by fixing F
appropriately, and new data types need only be concerned with implementing Applicative to do so as well.

scala mdoc:silent
def traverse[F[_]: Applicative, A, B](as: List[A])(f: A => F[B]): F[List[B]] =
  as.foldRight(Applicative[F].pure(List.empty[B])) { (a: A, acc: F[List[B]]) =>
    val fb: F[B] = f(a)
    Applicative[F].map2(fb, acc)(_ :: _)
  }

This function is provided by Cats via the Traverse[List] instance and syntax, which is covered in another
tutorial.

scala mdoc:silent
import cats.syntax.all._
scala mdoc
List(1, 2, 3).traverse(i => Some(i): Option[Int])

With this addition of traverse, we can now compose any number of independent effects, statically known or otherwise.

Apply - a weakened Applicative

A closely related type class is Apply which is identical to Applicative, modulo the pure
method. Indeed in Cats Applicative is a subclass of Apply with the addition of this method.

scala
trait Apply[F[_]] extends Functor[F] {
  def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
}

trait Applicative[F[_]] extends Apply[F] {
  def pure[A](a: A): F[A]

  def map[A, B](fa: F[A])(f: A => B): F[B] = ap(pure(f))(fa)
}

The laws for Apply are just the laws of Applicative that don't mention pure. In the laws given
above, the only law would be associativity.

One of the motivations for Apply's existence is that some types have Apply instances but not
Applicative - one example is Map[K, *]. Consider the behavior of pure for Map[K, A]. Given
a value of type A, we need to associate some arbitrary K to it but we have no way of doing that.

However, given existing Map[K, A] and Map[K, B] (or Map[K, A => B]), it is straightforward to
pair up (or apply functions to) values with the same key. Hence Map[K, *] has an Apply instance.

Syntax

Syntax for Applicative (or Apply) is available under the cats.implicits._ import. The most
interesting syntax is focused on composing independent effects: it works just like the methods
for composition we saw above (map3, tuple3, etc.), but achieves a slightly friendlier syntax
by enriching Scala's standard tuple types.

For example, we've already seen this code for mapping over three options together:

scala mdoc
Applicative[Option].map3(username, password, url)(attemptConnect)

With the applicative syntax, we can change this to the slightly shorter:

scala mdoc
import cats.syntax.all._

(username, password, url).mapN(attemptConnect)

We don't have to mention the type or specify the number of values we're composing
together, so there's a little less boilerplate here.

Another very useful Apply syntax is tupled, which allows a tuple of effectful values to be composed into a single effectful value containing a tuple.

scala mdoc
import cats.syntax.all._

val optPair: Option[(String, String)] = (username, password).tupled

See also Parallel variants

Both tupled and mapN have parallel variant operations, named parTupled and parMapN respectively. Regular tupled/mapN evaluate their effects from left to right ("sequentially"), while parTupled/parMapN evaluate in an indeterminate order, or in parallel.

The difference can be understood intuitively when the effect is an executable task, such as IO from Cats Effect. In this case, the parallel variants enable you to compose tuples of tasks into a single task that will run its sub-tasks concurrently.

Further Reading


Typeclasses Applicativemonaderror (`docs/typeclasses/applicativemonaderror.md`)

ApplicativeError and MonadError

API Documentation: @:api(cats.ApplicativeError), @:api(cats.MonadError)

Applicative Error

Description

ApplicativeError extends Applicative to provide handling for types
that represent the quality of an exception or an error, for example, Either[E, A]

TypeClass Definition

ApplicativeError is defined by the following trait

scala
trait ApplicativeError[F[_], E] extends Applicative[F] {
  def raiseError[A](e: E): F[A]
  def handleErrorWith[A](fa: F[A])(f: E => F[A]): F[A]
  def handleError[A](fa: F[A])(f: E => A): F[A]
  def attempt[A](fa: F[A]): F[Either[E, A]]
  //More functions elided
}

Use Case

`Either`

We can start with a less abstract way of performing a function. Here
we will divide one number by another.

scala mdoc:silent
def attemptDivide(x: Int, y: Int): Either[String, Int] = {
   if (y == 0) Left("divisor is zero")
   else {
      Right(x / y)
   }
}

While fine in the above approach, we can abstract the Either away
to support any other kind of "error" type without having to
create multiple functions with different "container" types.

scala mdoc:silent
import cats._
import cats.syntax.all._

def attemptDivideApplicativeError[F[_]](x: Int, y: Int)(implicit ae: ApplicativeError[F, String]): F[Int] = {
   if (y == 0) ae.raiseError("divisor is error")
   else {
      ae.pure(x/y)
   }
}

The above method summons ApplicativeError to provide behavior representing
an error where the end-user, based on type, will get their
appropriate response.

ApplicativeError is an Applicative, which means all Applicative
functions are available for use. One such method is pure, which will
return the F[_] representation, where F could represent Either.

Another method that you will see is raiseError, which will generate
the specific error type depending on what F[_] represents.
If F[_] is an Either, then ae.raiseError will return Left.
If F[_] represents a Validation, then ae.raiseError will return Invalid.
For example, if we want to use an Either as our error representation,
we can do the following:

scala mdoc:silent
type OnError[A] = Either[String, A]
val e: OnError[Int] = attemptDivideApplicativeError(30, 10)

or simply via assignment

scala mdoc:silent
val f: Either[String, Int] = attemptDivideApplicativeError(30, 10)

`Validated`

Given the same function attemptDivideApplicativeError, we can call that
function again but with a different return type, since the ApplicativeError
can support other "error" based types. Here we will use cats.data.Validated
when calling attemptDivideApplicativeError. Notice that
attemptDivideApplicativeError is the same as we defined above,
so we make no other changes.

scala mdoc:silent
import cats.syntax.all._
import cats.data.Validated

type MyValidated[A] = Validated[String, A]
val g = attemptDivideApplicativeError[MyValidated](30, 10)

We can inline the right projection type alias, MyValidated, doing the following:

scala mdoc:silent
val h = attemptDivideApplicativeError[({ type T[A] = Validated[String, A]})#T](30, 10)

Or we can use KindProjector
to make this more refined and readable

scala mdoc:silent
val j = attemptDivideApplicativeError[Validated[String, *]](30, 10)

It is an `Applicative` after all

As a Reminder, this is an Applicative
so all the methods of Applicative are available to you to use in
manipulating your values, ap, mapN, etc. In the following example, notice
we are using Applicative's map2, and of course, pure which also is a
form of Applicative.

scala mdoc:silent
import cats.syntax.all._
def attemptDivideApplicativeErrorWithMap2[F[_]](x: Int, y: Int)(implicit ae: ApplicativeError[F, String]): F[_] = {
   if (y == 0) ae.raiseError("divisor is error")
   else {
     val fa = ae.pure(x)
     val fb = ae.pure(y)
     ae.map2(fa, fb)(_ / _)
   }
}

Handling Errors

ApplicativeError has methods to handle what to do when F[_] represents an error.
In the following example, attemptDivideApplicativeErrorAbove2
creates an error representation if the divisor
is 0 or 1 with the message "Bad Math" or "Waste of Time".
We will feed the result from attemptDivideApplicativeErrorAbove2
into the handler method, where this method will pattern match on the message
and provide an alternative outcome.

scala mdoc:silent
import cats.syntax.all._
def attemptDivideApplicativeErrorAbove2[F[_]](x: Int, y: Int)(implicit ae: ApplicativeError[F, String]): F[Int] =
  if (y == 0) ae.raiseError("Bad Math")
  else if (y == 1) ae.raiseError("Waste of Time")
  else ae.pure(x / y)

def handler[F[_]](f: F[Int])(implicit ae: ApplicativeError[F, String]): F[Int] = {
  ae.handleError(f) {
    case "Bad Math"      => -1
    case "Waste of Time" => -2
    case _               => -3
  }
}

Running the following will result in Right(-1)

scala mdoc:silent
handler(attemptDivideApplicativeErrorAbove2(3, 0))

handleErrorWith is nearly the same as handleError but
instead of returning a value A, we will return F[_]. This could provide us
the opportunity to make it very abstract and return a value from a Monoid.empty.

scala mdoc:silent
def handlerErrorWith[F[_], M[_], A](f: F[A])(implicit F: ApplicativeError[F, String], M:Monoid[A]): F[A] = {
  F.handleErrorWith(f)(_ => F.pure(M.empty))
}

Running the following will result in Right(0)

scala mdoc:silent
handlerErrorWith(attemptDivideApplicativeErrorAbove2(3, 0))

Handling Exceptions

There will inevitably come a time when your nice ApplicativeError code will
have to interact with exception-throwing code. Handling such situations is easy
enough.

scala mdoc
def parseInt[F[_]](input: String)(implicit F: ApplicativeError[F, Throwable]): F[Int] =
  try {
    F.pure(input.toInt)
  } catch {
    case nfe: NumberFormatException => F.raiseError(nfe)
  }

parseInt[Either[Throwable, *]]("123")
parseInt[Either[Throwable, *]]("abc")

However, this can get tedious quickly. ApplicativeError has a catchOnly
method that allows you to pass it a function, along with the type of exception
you want to catch, and does the above for you.

scala mdoc:nest
def parseInt[F[_]](input: String)(implicit F: ApplicativeError[F, Throwable]): F[Int] =
  F.catchOnly[NumberFormatException](input.toInt)

parseInt[Either[Throwable, *]]("abc")

If you want to catch all (non-fatal) throwables, you can use catchNonFatal.

scala mdoc:nest
def parseInt[F[_]](input: String)(implicit F: ApplicativeError[F, Throwable]): F[Int] = F.catchNonFatal(input.toInt)

parseInt[Either[Throwable, *]]("abc")

MonadError

Description

Since a Monad extends an Applicative, there is naturally a MonadError that
will extend the functionality of the ApplicativeError to provide flatMap
composition.

TypeClass Definition

The Definition for MonadError extends Monad which provides the
methods, flatMap, whileM_. MonadError also provides error
handling methods like ensure, ensureOr, adaptError, rethrow.

scala
trait MonadError[F[_], E] extends ApplicativeError[F, E] with Monad[F] {
  def ensure[A](fa: F[A])(error: => E)(predicate: A => Boolean): F[A] 
  def ensureOr[A](fa: F[A])(error: A => E)(predicate: A => Boolean): F[A]
  def adaptError[A](fa: F[A])(pf: PartialFunction[E, E]): F[A]
  def rethrow[A, EE <: E](fa: F[Either[EE, A]]): F[A]
}

Use Case

Given a method that accepts a tuple of coordinates, it finds the closest city. For this example
we will hard-code "Minneapolis, MN," but you can imagine for the sake of
In this example, you would either consult a database or a web service.

scala mdoc:silent
def getCityClosestToCoordinate[F[_]](x: (Int, Int))(implicit ae: ApplicativeError[F, String]): F[String] = {
  ae.pure("Minneapolis, MN")
}

Next, let's follow up with another method, getTemperatureByCity, that given a
city, possibly a city that was just discovered by its coordinates, we get
the temperature for that city. Here, for the sake of demonstration,
we are hardcoding a temperature of 78°F.

scala mdoc:silent
def getTemperatureByCity[F[_]](city: String)(implicit ae: ApplicativeError[F, String]): F[Int] = {
  ae.pure(78)
}

With the methods that we will compose in place let's create a method that will
compose the above methods using a for comprehension which
interprets to a flatMap-map combination.

getTemperatureByCoordinates's parameterized type
[F[_]:MonadError[*[_], String] injects F[_] into MonadError[*[_], String];
thus if the "error type" you wish to use is Either[String, *], the Either
would be placed in the hole of MonadError, in this case,
MonadError[Either[String, *], String]

getTemperatureByCoordinates accepts a Tuple2 of Int and Int and
returns F, which represents our MonadError, which can be a type like Either or
Validated. In the method, since getCityClosestToCoordinate and
getTemperatureByCity both return potential error types and they are monadic, we can
compose them with a for comprehension.

scala mdoc:silent
def getTemperatureByCoordinates[F[_]: MonadError[*[_], String]](x: (Int, Int)): F[Int] = {
  for { c <- getCityClosestToCoordinate[F](x)
        t <- getTemperatureByCity[F](c) } yield t
}

We can call getTemperatureByCoordinates with the following sample, which will return 78.

scala mdoc:silent
type MyEither[A] = Either[String, A]
getTemperatureByCoordinates[MyEither]((44, 93))

With TypeLevel Cats, how you structure your methods is up to you: if you wanted to
create getTemperatureByCoordinates without a Scala
context bound for MonadError,
but create an implicit parameter for your MonadError you can have access to some
additional methods.

In the following example, we create an implicit MonadError parameter
and call it me. Using the me reference, we can call any one of its
specialized methods, like raiseError, to raise an error representation
when things go wrong.

scala mdoc:silent
def getTemperatureByCoordinatesAlternate[F[_]](x: (Int, Int))(implicit me: MonadError[F, String]): F[Int] = {
  if (x._1 < 0 || x._2 < 0) me.raiseError("Invalid Coordinates")
  else for { c <- getCityClosestToCoordinate[F](x)
        t <- getTemperatureByCity[F](c) } yield t
}

Typeclasses Applicativetraverse (`docs/typeclasses/applicativetraverse.md`)

Applicative and Traversable Functors

An example from the standard library

One of the most useful functions when working with scala.concurrent.Future is Future.traverse, presented below
in a simplified form.

scala mdoc:silent
import scala.concurrent.{ExecutionContext, Future}

def traverseFuture[A, B](as: List[A])(f: A => Future[B])(implicit ec: ExecutionContext): Future[List[B]] =
  Future.traverse(as)(f)

traverseFuture takes a List[A] and for each A in the list applies the function f to it, gathering results
as it goes along. f is often referred to as an effectful function, where the Future effect is running the computation
concurrently, presumably on another thread. This effect is apparent in the result of the function, which has
gathered results inside Future.

But what if the effect we wanted wasn't Future? What if instead of concurrency for our effect we wanted validation
(Option, Either, Validated) or State ? It turns out we can abstract out the commonalities between all these
data types and write a generic traverse function once and for all. We can even go further and abstract over data
types that can be traversed over such as List, Vector, and Option.

In this series we will build up the machinery needed to generalize the standard library's Future.traverse into
its fully abstract and most reusable form.

If you'd like to read the published literature on these ideas, some good starting points are
"Applicative Programming with Effects" by McBride and Patterson, and
"The Essence of the Iterator Pattern" by Gibbons and Oliveira.


Typeclasses Arrow (`docs/typeclasses/arrow.md`)

Arrow

API Documentation: @:api(cats.arrow.Arrow)

Arrow is a type class for modeling composable relationships between two types. One example of such a composable relationship is function A => B; other examples include cats.data.Kleisli(wrapping an A => F[B], also known as ReaderT), and cats.data.Cokleisli(wrapping an F[A] => B). These type constructors all have Arrow instances. An arrow F[A, B] can be thought of as representing a computation from A to B with some context, just like a functor/applicative/monad F[A] represents a value A with some context.

Having an Arrow instance for a type constructor F[_, _] means that an F[_, _] can be composed and combined with other F[_, _]s. You will be able to do things like:

  • Lifting a function ab: A => B into arrow F[A, B] with Arrow[F].lift(ab). If F is Function1 then A => B is the same as F[A, B] so lift is just the identity function.
  • Composing fab: F[A, B] and fbc: F[B, C] into fac: F[A, C] with Arrow[F].compose(fbc, fab), or fab >>> fbc. If F is Function1 then >>> becomes an alias for andThen.
  • Taking two arrows fab: F[A, B] and fcd: F[C, D] and combining them into F[(A, C), (B, D)] with fab.split(fcd) or fab *** fcd. The resulting arrow takes two inputs and processes them with two arrows, one for each input.
  • Taking an arrow fab: F[A, B] and turning it into F[(A, C), (B, C)] with fab.first. The resulting arrow takes two inputs, processes the first input and leaves the second input as it is. A similar method, fab.second, turns F[A, B] into F[(C, A), (C, B)].

Examples

`Function1`

scala.Function1 has an Arrow instance, so you can use all the above methods on Function1. The Scala standard library has the compose and andThen methods for composing Function1s, but the Arrow instance offers more powerful options.

Suppose we want to write a function meanAndVar, that takes a List[Int] and returns the pair of mean and variance. To do so, we first define a combine function that combines two arrows into a single arrow, which takes an input and processes two copies of it with two arrows. combine can be defined in terms of Arrow operations lift, >>> and ***:

scala mdoc:silent
import cats.arrow.Arrow
import cats.syntax.all._

def combine[F[_, _]: Arrow, A, B, C](fab: F[A, B], fac: F[A, C]): F[A, (B, C)] =
  Arrow[F].lift((a: A) => (a, a)) >>> (fab *** fac)

We can then create functions mean: List[Int] => Double, variance: List[Int] => Double and meanAndVar: List[Int] => (Double, Double) using the combine method and Arrow operations:

scala mdoc:silent
val mean: List[Int] => Double =
    combine((_: List[Int]).sum, (_: List[Int]).size) >>> {case (x, y) => x.toDouble / y}

val variance: List[Int] => Double =
  // Variance is mean of square minus square of mean
  combine(((_: List[Int]).map(x => x * x)) >>> mean, mean) >>> {case (x, y) => x - y * y}

val meanAndVar: List[Int] => (Double, Double) = combine(mean, variance)
scala mdoc
meanAndVar(List(1, 2, 3, 4))

Of course, a more natural way to implement mean and variance would be:

scala mdoc:silent
val mean2: List[Int] => Double = xs => xs.sum.toDouble / xs.size

val variance2: List[Int] => Double = xs => mean2(xs.map(x => x * x)) - scala.math.pow(mean2(xs), 2.0)

However, Arrow methods are more general and provide a common structure for type constructors that have Arrow instances. They are also a more abstract way of stitching computations together.

`Kleisli`

A Kleisli[F[_], A, B] represents a function A => F[B]. You cannot directly compose an A => F[B] with a B => F[C] with functional composition, since the codomain of the first function is F[B] while the domain of the second function is B; however, since Kleisli is an arrow (as long as F is a monad), you can easily compose Kleisli[F[_], A, B] with Kleisli[F[_], B, C] using Arrow operations.

Suppose you want to take a List[Int], and return the sum of the first and the last element (if exists). To do so, we can create two Kleislis that find the headOption and lastOption of a List[Int], respectively:

scala mdoc:silent
import cats.data.Kleisli

val headK = Kleisli((_: List[Int]).headOption)
val lastK = Kleisli((_: List[Int]).lastOption)

With headK and lastK, we can obtain the Kleisli arrow we want by combining them, and composing it with _ + _:

scala mdoc:silent
val headPlusLast = combine(headK, lastK) >>> Arrow[Kleisli[Option, *, *]].lift(((_: Int) + (_: Int)).tupled)
scala mdoc
headPlusLast.run(List(2, 3, 5, 8))
headPlusLast.run(Nil)

`FancyFunction`

In this example let's create our own Arrow. We shall create a fancy version of Function1 called FancyFunction, that is capable of maintaining states. We then create an Arrow instance for FancyFunction and use it to compute the moving average of a list of numbers.

scala mdoc:silent
case class FancyFunction[A, B](run: A => (FancyFunction[A, B], B))

That is, given an A, it not only returns a B, but also returns a new FancyFunction[A, B]. This sounds similar to the State monad (which returns a result and a new State from an initial State), and indeed, FancyFunction can be used to perform stateful transformations.

To run a stateful computation using a FancyFunction on a list of inputs, and collect the output into another list, we can define the following runList helper function:

scala mdoc:silent
def runList[A, B](ff: FancyFunction[A, B], as: List[A]): List[B] = as match {
  case h :: t =>
    val (ff2, b) = ff.run(h)
    b :: runList(ff2, t)
  case _ => List()
}

In runList, the head element in List[A] is fed to ff, and each subsequent element is fed to a FancyFunction which is generated by running the previous FancyFunction on the previous element. If we have an as: List[Int], and an avg: FancyFunction[Int, Double] which takes an integer and computes the average of all integers it has seen so far, we can call runList(avg, as) to get the list of moving average of as.

Next let's create an Arrow instance for FancyFunction and see how to implement the avg arrow. To create an Arrow instance for a type F[A, B], the following abstract methods need to be implemented:

text
def lift[A, B](f: A => B): F[A, B]

def id[A]: F[A, A]

def compose[A, B, C](f: F[B, C], g: F[A, B]): F[A, C]

def first[A, B, C](fa: F[A, B]): F[(A, C), (B, C)]

Thus the Arrow instance for FancyFunction would be:

scala mdoc:silent
implicit val arrowInstance: Arrow[FancyFunction] = new Arrow[FancyFunction] {

  override def lift[A, B](f: A => B): FancyFunction[A, B] = FancyFunction(lift(f) -> f(_))

  override def first[A, B, C](fa: FancyFunction[A, B]): FancyFunction[(A, C), (B, C)] = FancyFunction {case (a, c) =>
    val (fa2, b) = fa.run(a)
    (first(fa2), (b, c))
  }

  override def id[A]: FancyFunction[A, A] = FancyFunction(id -> _)

  override def compose[A, B, C](f: FancyFunction[B, C], g: FancyFunction[A, B]): FancyFunction[A, C] = FancyFunction {a =>
    val (gg, b) = g.run(a)
    val (ff, c) = f.run(b)
    (compose(ff, gg), c)
  }
}

Once we have an Arrow[FancyFunction], we can start to do interesting things with it. First, let's create a method accum that returns a FancyFunction, which accumulates values fed to it using the accumulation function f and the starting value b:

scala mdoc:silent
def accum[A, B](b: B)(f: (A, B) => B): FancyFunction[A, B] = FancyFunction {a =>
  val b2 = f(a, b)
  (accum(b2)(f), b2)
}
scala mdoc
runList(accum[Int, Int](0)(_ + _), List(6, 5, 4, 3, 2, 1))

To make the aformentioned avg arrow, we need to keep track of both the count and the sum of the numbers we have seen so far. To do so, we will combine several FancyFunctions to get the avg arrow we want.

We first define arrow sum in terms of accum, and define arrow count by composing _ => 1 with sum:

scala mdoc:silent
import cats.kernel.Monoid

def sum[A: Monoid]: FancyFunction[A, A] = accum(Monoid[A].empty)(_ |+| _)
def count[A]: FancyFunction[A, Int] = Arrow[FancyFunction].lift((_: A) => 1) >>> sum

Finally, we create the avg arrow in terms of the arrows we have so far:

scala mdoc:silent
def avg: FancyFunction[Int, Double] =
  combine(sum[Int], count[Int]) >>> Arrow[FancyFunction].lift{case (x, y) => x.toDouble / y}
scala mdoc
runList(avg, List(1, 10, 100, 1000))

Typeclasses Arrowchoice (`docs/typeclasses/arrowchoice.md`)

Arrow Choice

API Documentation: @:api(cats.arrow.Choice)

Usually we deal with function more often, we're so familiar with A => B.

If we have two functions A => C and B => C, how can we compose them into a single function that can take either A or B and produce a C?

So basically we just look for a function that has type (A => C) => (B => C) => (Either[A, B] => C).

This is exactly typeclass Choice provided, if we make => more generic such as F[_,_], you will get a Choice

scala
trait Choice[F[_, _]] {
  def choice[A, B, C](fac: F[A, C], fbc: F[B, C]): F[Either[A, B], C]
}

Note the infix notation of choice is |||.

Middleware

A very useful case of Choice is middleware in HTTP server.

Take Http4s for example:

HttpRoutes[F] in Http4s is defined as Kleisli

scala
type HttpRoutes[F[_]] = Kleisli[OptionT[F, *], Request[F], Response[F]]
// defined type HttpRoutes
def routes[F[_]]: HttpRoutes[F] = ???
// defined function routes

If we like to have an authentication middleware that composes the route, we can simply define middleware as:

scala
type Middleware[F[_]] = Kleisli[OptionT[F, *], Request[F], Either[Response[F], Request[F]]]
// defined type Middleware
def auth[F[_]]: Middleware[F] = ???
// defined function auth

Which means the Request[F] goes through the middleware, will become option of Either[Response[F], Request[F]], where Left means the request is denied and return immediately, Right means the authentication is OK and request will get pass.

Now we need to define what we should do when middleware returns Left:

scala
def reject[F[_]:Monad]: Kleisli[OptionT[F, *], Response[F], Response[F]] = Kleisli.ask[OptionT[F, *], Response[F]]
// defined function reject

Now compose middleware with route

scala
def authedRoute[F[_]:Monad] = auth[F] andThen (reject[F] ||| routes[F])
// defined function authedRoute

You will then get a new route that has authentication ability by composing Kleisli.

HTTP Response

Another example will be HTTP response handler.

scala
val resp: IO[Either[Throwable, String]] = httpClient.expect[String](uri"https://google.com/").attempt

attempt is syntax from MonadError

When we need to handle error, without Choice the handler would be something like:

scala
resp.flatMap{
  case Left => ???
  case Right => ???
}

With Choice there will be more composable solution without embedded logic in pattern matching:

scala
def recover[A](error: Throwable): IO[A] = ???
def processResp[A](resp: String): IO[A] = ???

resp >>= (recover _ ||| processResp _)

`ArrowChoice`

ArrowChoice is an extended version of Choice, which has one more method choose, with syntax +++

scala
trait ArrowChoice[F[_, _]] extends Choice[F] {
  def choose[A, B, C, D](f: F[A, C])(g: F[B, D]): F[Either[A, B], Either[C, D]]
}

With the middleware example, you can think ArrowChoice is middleware of middleware.

For example if we want to append log to middleware of auth, that can log both when rejected response and pass request:

scala
def logReject[F[_]]: Kleisli[OptionT[F, *], Response[F], Response[F]] = ???
// defined function logReject
def logThrough[F[_]]: Kleisli[OptionT[F, *], Request[F], Request[F]] = ???
// defined function logThrough

See how easy to compose log functionality into our authedRoute:

scala
def authedRoute[F[_]:Monad] = auth[F] andThen (logReject[F] +++ logThrough[F]) andThen (reject[F] ||| routes[F])
// defined function authedRoute

Typeclasses Bifoldable (`docs/typeclasses/bifoldable.md`)

Bifoldable

API Documentation: @:api(cats.Bifoldable)

Bifoldable[F[_,_]] instances identify data structures with two independent Foldable that fold to the same summary value.

As a reminder Foldable is implemented in terms of foldLeft and foldRight; similarly Bifoldable is implemented in terms of:

scala
//eagerly performs a left-associative bi-fold over `fab`
  def bifoldLeft[A, B, C](fab: F[A, B], c: C)(f: (C, A) => C, g: (C, B) => C): C

  //lazily performs a right-associative bi-fold over `fab`
  def bifoldRight[A, B, C](fab: F[A, B], c: Eval[C])(f: (A, Eval[C]) => Eval[C], g: (B, Eval[C]) => Eval[C]): Eval[C]

and by implementing those 2 methods you also get:

scala
def bifold[A, B](fab: F[A, B])(implicit A: Monoid[A], B: Monoid[B]): (A, B)

  def bifoldMap[A, B, C](fab: F[A, B])(f: A => C, g: B => C)(implicit C: Monoid[C]): C

A lawful instance must have bifoldLeft\Right consistent with bifoldMap; left\right bi-folds based on associative
functions should output similar results.

Either and Validated as Bifoldable

Assume multiple input paths and system requests that end up as Either[Exception, *] or Validated[Exception, *].
The requirement is to track the amount of errors and store the content of valid requests.

First add the implicits:

scala mdoc
import cats._
import cats.data._
import cats.syntax.all._

then let's define a summary class capable of storing this info:

scala mdoc
case class Report(entries: Chain[String], errors: Int) {
  def withEntries(entry: String): Report =
    this.copy(entries = entries :+ entry)

  def withError: Report =
    this.copy(errors = errors + 1)
}

Bifoldable is useful to get a summary value from F[_,_] data types:

scala mdoc
def update[F[_, _]: Bifoldable](current: Report)(result: F[Exception, String]): Report =
  result.bifoldLeft(current)((acc, _) => acc.withError, (acc, user) => acc.withEntries(user))

Here is the system input:

scala mdoc
val validated =
  List(
    Validated.valid[Exception, String]("valid request 1"),
    Validated.valid[Exception, String]("valid request 2"),
    Validated.invalid[Exception, String](new RuntimeException("Not a valid request"))
  )

val attempted =
  List(
    Either.right[Exception, String]("valid request 1"),
    Either.right[Exception, String]("valid request 2"),
    Either.left[Exception, String](new RuntimeException("Not a valid request"))
  )

and bi-fold each value into the accumulator:

scala mdoc
val empty = Report(Chain.empty, 0)

validated
  .foldl(empty)((acc, validation) => update(acc)(validation))

attempted
  .foldl(empty)((acc, attempt) => update(acc)(attempt))

Tuple as Bifoldable

Assume we have (String, String, Int) and to get our summary we need _1 and _3.
The existing implementations for (*, *), (T0, *, *), (T0, T1, *, *) .. aren't useful.

Let's make a new Bifoldable instance:

scala mdoc
implicit def bifoldableForTuple3[A0]: Bifoldable[(*, A0, *)] =
  new Bifoldable[(*, A0, *)] {
    def bifoldLeft[A, B, C](fa: (A, A0, B), c: C)(f: (C, A) => C, g: (C, B) => C): C =
      g(f(c, fa._1), fa._3)

    def bifoldRight[A, B, C](fa: (A, A0, B), c: Eval[C])(f: (A, Eval[C]) => Eval[C], g: (B, Eval[C]) => Eval[C]): Eval[C] =
      g(fa._3, f(fa._1, c))
  }

As we were saying in the beginning a lawful Bifoldable should have bifoldLeft\Right consistent with bifoldMap.
Let's check our instance:

scala mdoc
//(name, age, occupation)
val description = ("Niki", 22, "Developer")

val expected =
  Bifoldable[(*, Int, *)].bifoldMap(description)(s => s, s => s)

val left =
 Bifoldable[(*, Int, *)].bifoldLeft(description, Monoid[String].empty)(
  (acc, s) => acc |+| s,
  (acc, s) => acc |+| s
 )

val right =
  Bifoldable[(*, Int, *)].bifoldRight(description, Eval.later(Monoid[String].empty))(
    (s, acc) => acc.map(_ |+| s),
    (s, acc) => acc.map(_ |+| s)
  )

left === expected
right.value === expected

NOTE: This instance would not be lawful if bifoldRight in particular would use a different ordering.

Going from right to left as opposed to left to right means:

scala mdoc
def bifoldRight[A, B, C](fa: (A, Int, B), c: Eval[C])(f: (A, Eval[C]) => Eval[C], g: (B, Eval[C]) => Eval[C]): Eval[C] =
   f(fa._1, g(fa._3, c))

and it would also reverse the output making the instance unlawful:

scala mdoc
val reversedRight =
 bifoldRight(description, Eval.later(Monoid[String].empty))(
    (s, acc) => acc.map(_ |+| s),
    (s, acc) => acc.map(_ |+| s)
  )

reversedRight.value === expected

Bifoldable `compose`

If F[_,_] and G[_,_] have Bifoldable instances then so does F[G[_,_],G[_,_]].

Examples for (Either[*, *], Either[*, *]) and ((*, *), (*, *)):

scala mdoc
Bifoldable[(*, *)]
  .compose(Bifoldable[(*, *)])
  .bifoldLeft((("name1 ", 1000),("name2 ", 2000)), List.empty[String])((acc, name) => acc :+ name, (acc, _) => acc)

Bifoldable[(*, *)]
  .compose(Bifoldable[Either[*, *]])
  .bifold((Left(1), Right(2)))

Typeclasses Bifunctor (`docs/typeclasses/bifunctor.md`)

Bifunctor

API Documentation: @:api(cats.Bifunctor)

Bifunctor takes two type parameters instead of one, and is a functor in both
of these parameters. It defines a function bimap, which allows for mapping over both
arguments at the same time. Its signature is as follows:

scala
def bimap[A, B, C, D](fab: F[A, B])(f: A => C, g: B => D): F[C, D]

Either as a Bifunctor

Probably the most widely used Bifunctor instance is the Either data type.

Say you have a value that is either an error or a ZonedDateTime instance.
You also want to react to both possibilities - if there was a failure, you want to
convert it to your own DomainError, and if the result was a success, you want to
convert it to an UNIX timestamp.

scala mdoc:silent
import cats._
import cats.syntax.all._
import java.time._

case class DomainError(message: String)

def dateTimeFromUser: Either[Throwable, ZonedDateTime] = 
  Right(ZonedDateTime.now())  // Example definition
scala mdoc
dateTimeFromUser.bimap(
  error => DomainError(error.getMessage),
  dateTime => dateTime.toEpochSecond
)

Bifunctor also defines a convenience function called leftMap, which is defined as follows:

scala
def leftMap[A, B, C](fab: F[A, B])(f: A => C): F[C, B] = bimap(fab)(f, identity)

There is no rightMap however - use map instead. The reasoning behind this is that in Cats, the instances of
Bifunctor are also mostly instances of Functor, as it is the case with Either.

Tuple2 as a Bifunctor

Another very popular Bifunctor is that for the Tuple2 data type, or (A, B) for types A and B.

Let's say we have a list of balances and want divide them by the number of months in the lifetime of the account holder. The balances are given in cents.
A bit contrived, but we want an average contribution per month to the given account. We want the result in dollars per month. The lifetime is given in the number of years the account has been active.

scala mdoc
val records: List[(Int, Int)] = List((450000, 3), (770000, 4), (990000, 2), (2100, 4), (43300, 3))

def calculateContributionPerMonth(balance: Int, lifetime: Int) = balance / lifetime

val result: List[Int] =
  records.map(
      record => record.bimap(
        cents => cents / 100,
        years => 12 * years
      )
    ).map((calculateContributionPerMonth _).tupled)

As you can see, this instance makes it convenient to process two related pieces of data in independent ways, especially when there is no state relationship between the two until processing is complete.

Note that, just as with the bifunctor for Either, we do not have a rightMap function since the relevant instances of Bifunctor induce a Functor in the second argument, so we just use map.


Typeclasses Bimonad (`docs/typeclasses/bimonad.md`)

Bimonad

API Documentation: @:api(cats.Bimonad)

The Bimonad trait directly extends Monad and Comonad without introducing new methods. Bimonad is
different from other Bi typeclasses like Bifunctor, Bifoldable or Bitraverse where the prefix describes
a F[_, _]. The Bimonad is a F[_] and the Bi prefix has a different meaning here: it's both a Monad and a Comonad.
Keep in mind Bimonad has its own added laws so something that is both monadic
and comonadic may not necessarily be a lawful Bimonad.

If you use Bimonad as a convenience type such that:

scala
def f[T[_]: Monad: Comonad, S](fa: T[S]): S

is re-written to:

scala
def f[T[_]: Bimonad, S](fa: T[S]): S

then T[_] also needs to respect an extra set of laws.

NonEmptyList as a Bimonad

NonEmptyList[_] is a lawful Bimonad so you can chain computations (like a Monad) and extract the result at the end (like a Comonad).

Here is a possible implementation:

scala mdoc
import cats._
import cats.data._
import cats.syntax.all._

implicit val nelBimonad: Bimonad[NonEmptyList] =
  new Bimonad[NonEmptyList] {

    // in order to have a lawful bimonad `pure` and `extract` need to respect: `nelBimonad.extract(nelBimonad.pure(a)) <-> a`
    override def pure[A](a: A): NonEmptyList[A] =
      NonEmptyList.one(a)

    override def extract[A](fa: NonEmptyList[A]): A =
      fa.head

    // use coflatMap from NonEmptyList
    override def coflatMap[A, B](fa: NonEmptyList[A])(f: NonEmptyList[A] => B): NonEmptyList[B] =
      fa.coflatMap(f)

    // use flatMap from NonEmptyList
    override def flatMap[A, B](fa: NonEmptyList[A])(f: A => NonEmptyList[B]): NonEmptyList[B] =
      fa.flatMap(f)

    // the tailRecM implementation is not the subject of this material
    // as an exercise try to implement it yourself
    override def tailRecM[A, B](a: A)(fn: A => NonEmptyList[Either[A, B]]): NonEmptyList[B] =
      ???
  }

Note the equivalence:

scala mdoc
nelBimonad.pure(true).extract === NonEmptyList.one(true).head

Using generic bimonad syntax we could define a function that appends and extracts a configuration:

scala mdoc
def make[T[_]: Bimonad](config: T[String]): String = 
  config
    .flatMap(c => Bimonad[T].pure(c + " with option A"))
    .flatMap(c => Bimonad[T].pure(c + " with option B"))
    .flatMap(c => Bimonad[T].pure(c + " with option C"))
    .extract

This works with one element non-empty lists:

scala mdoc
make(NonEmptyList.one("config"))

Function0[_] and Eval[_] are also lawful bimonads so the following calls are also valid:

scala mdoc
make(() => "config")

make(Eval.later("config"))

Typeclasses Comonad (`docs/typeclasses/comonad.md`)

Comonad

API Documentation: @:api(cats.Comonad)

Comonad is a Functor and provides duals of the Monad pure
and flatMap functions. A dual to a function has the same types but the
direction of the arrows are reversed. Whether or not that is useful, or even possible,
depends on the particular type. For a more formal definition of duality, please
refer to https://ncatlab.org/nlab/show/duality.

extract

Monads have pure from Applicative which gives you the ability to wrap
a value A using the type constructor giving an F[A]. Comonad has
extract which instead takes an F[A] and extracts the A. Therefore, to be
able to implement extract we must have a type of which we are certain
we can get an A from an F[A]. For example we cannot always get an A
from a List[A] because if the list is empty there is nothing to get.

For the same reason, Option doesn't have a Comonad instance, because we
cannot always get an A from an Option, it may be empty too.

Some examples that we can implement Comonad for include OneAnd, Tuple2
and the "non empty" collections.

First some imports.

scala mdoc:silent
import cats._
import cats.data._
import cats.syntax.all._
import cats.instances.list._

NonEmptyList has a Comonad instance and its implementation of extract
simply returns the head element of the list, which we know we will always
have.

scala mdoc
NonEmptyList.of(1,2,3).extract

coflatMap

coflatMap is the dual of Monad's flatMap. While flatMap allows us to chain
together operations in a monadic context, coflatMap takes a value in some context
F[A] and a function F[A] => B and returns a new value in a context F[B].

The default implementation of coflatMap for NonEmptyList will pass the supplied
function with the whole list, then the tail of that, then the tail of that and so
on. This is illustrated below.

scala mdoc
NonEmptyList.of(1,2,3,4,5).coflatMap(identity)

CoflatMap

While FlatMap is a weaker version of Monad that doesn't have the pure function,
CoflatMap is a Comonad without the extract function. There are many instances
of type classes in Cats that implement CoflatMap but not Comonad.

For example we cannot write extract for Option[A] because there's no way to
pull an A out of nowhere if the Option is empty.

scala mdoc:silent
def extract[A](fa : Option[A]): A = fa match {
	case Some(a) => a
	case None => ??? // What now?
}

Another example is List. Remember we cannot write extract for list because lists
can be empty, but we can implement the coflatMap and it works identically to the
one shown above for NonEmptyList.

scala mdoc
List(1,2,3,4,5).coflatMap(identity)

Typeclasses Contravariant (`docs/typeclasses/contravariant.md`)

Contravariant

API Documentation: @:api(cats.Contravariant)

The Contravariant type class is for functors that define a contramap
function with the following type:

scala
def contramap[A, B](fa: F[A])(f: B => A): F[B]

It looks like regular (also called Covariant) Functor's map,
but with the f transformation reversed.

Generally speaking, if you have some context F[A] for type A,
and you can get an A value out of a B value — Contravariant allows you to get the F[B] context for B.

Examples of Contravariant instances are Show and scala.math.Ordering (along with cats.kernel.Order).

Contravariant instance for Show.

Say we have a class Money with a Show instance, and a Salary class:

scala mdoc:silent
import cats._

import cats.syntax.all._

case class Money(amount: Int)
case class Salary(size: Money)

implicit val showMoney: Show[Money] = Show.show(m => s"$$${m.amount}")

If we want to show a Salary instance, we can just convert it to a Money instance and show that instead.

Let's use Show's Contravariant:

scala mdoc
implicit val showSalary: Show[Salary] = showMoney.contramap(_.size)

Salary(Money(1000)).show

Contravariant instance for scala.math.Ordering.

The Show example is trivial and quite far-fetched, let's see how Contravariant can help with orderings.

The scala.math.Ordering type class defines comparison operations, e.g. compare:

scala mdoc
Ordering.Int.compare(2, 1)
Ordering.Int.compare(1, 2)

There's also a method, called by, that creates new Orderings out of existing ones:

scala
def by[T, S](f: T => S)(implicit ord: Ordering[S]): Ordering[T]

In fact, it is just contramap, defined in a slightly different way! We supply T => S to receive F[S] => F[T] back.

So let's use it to our advantage and get Ordering[Money] for free:

scala mdoc
// we need this for `<` to work
import scala.math.Ordered._

implicit val moneyOrdering: Ordering[Money] = Ordering.by(_.amount)

Money(100) < Money(200)

Subtyping

Contravariant functors have a natural relationship with subtyping, dual to that of covariant functors:

scala mdoc
class A
class B extends A
val b: B = new B
val a: A = b
val showA: Show[A] = Show.show(a => "a!")
val showB1: Show[B] = showA.contramap(b => b: A)
val showB2: Show[B] = showA.contramap(identity[A])
val showB3: Show[B] = Contravariant[Show].narrow[A, B](showA)

Subtyping relationships are "lifted backwards" by contravariant functors, such that if F is a
lawful contravariant functor and B <: A then F[A] <: F[B], which is expressed by Contravariant.narrow.


Typeclasses Contravariantmonoidal (`docs/typeclasses/contravariantmonoidal.md`)

Contravariant Monoidal

API Documentation: @:api(cats.ContravariantMonoidal)

The ContravariantMonoidal type class is for Contravariant functors that can define a
product function and a unit function.

scala mdoc:silent
import cats.Contravariant

trait ContravariantMonoidal[F[_]] extends Contravariant[F] {
  def unit: F[Unit]

  def product[A, B](fa: F[A], fc: F[B]): F[(A, B)]

  def contramap2[A, B, C](fb: F[B], fc: F[C])(f: A => (B, C)): F[A] =
    contramap(product(fb, fc))(f)
}

Notice that this allows us to define the contramap2 function, much like
the map2 function and the pure function on the Applicative typeclass, but in reverse.

Basically, if you have two contexts F[B] and F[C] for types
B and C, as well as a way to produce types B and C simultaneously
from a type A, then ContravariantMonoidal allows you to obtain
a context F[A] for the type A.

Examples of ContravariantMonoidal instances are Eq and Const,
but there are also interesting instances for other types.

Predicates Have `ContravariantMonoidal`

An example application would be the case of predicates. Consider the type,

scala mdoc:silent:reset
import cats._

import cats.syntax.all._

case class Predicate[A](run: A => Boolean)

Then, we can exhibit a ContravariantMonoidal for Predicate by basing it on the
Monoid for Boolean via && as,

scala mdoc:silent
implicit val contravariantMonoidalPredicate: ContravariantMonoidal[Predicate] =
  new ContravariantMonoidal [Predicate] {
    def unit: Predicate[Unit] = Predicate[Unit](Function.const(true))

    def product[A, B](fa: Predicate[A], fb: Predicate[B]): Predicate[(A, B)] =
      Predicate(x => fa.run(x._1) && fb.run(x._2))

    def contramap[A, B](fa: Predicate[A])(f: B => A): Predicate[B] =
      Predicate(x => fa.run(f(x)))
  }

We could have also used false and ||, but the "and" version
tends to be a little more convenient for this application.

Just like for Contravariant, we can contramap to
pull Predicates back along functions.

scala mdoc
case class Money(value: Long)
def isEven: Predicate[Long] = Predicate(_ % 2 == 0)

def isEvenMoney: Predicate[Money] = isEven.contramap(_.value)

isEvenMoney.run(Money(55))

We can also lift functions contravariantly into
the context instead of contramapping repeatedly.

scala mdoc
def times2Predicate: Predicate[Long] => Predicate[Long] =
  ContravariantMonoidal[Predicate].liftContravariant((x: Long) => 2*x)

def liftMoney: Predicate[Long] => Predicate[Money] =
  ContravariantMonoidal[Predicate].liftContravariant(_.value)

def trivial = times2Predicate(isEven)
trivial.run(2)
trivial.run(5)

More interestingly, we can combine multiple predicates using
a contramapN.

scala mdoc
case class Transaction(value: Money, payee: String)

def isEvan: Predicate[String] = Predicate(_ == "Evan")

def isGreaterThan50Dollars: Predicate[Money] = liftMoney(Predicate(_ > 50))

def isEvenPaymentToEvanOfMoreThan50 =
  (isEvenMoney, isGreaterThan50Dollars, isEvan).contramapN(
    (trans: Transaction) => (trans.value, trans.value, trans.payee))

isEvenPaymentToEvanOfMoreThan50.run(Transaction(Money(56), "Evan"))

Typeclasses Eq (`docs/typeclasses/eq.md`)

Eq

API Documentation: @:api(cats.kernel.Eq)

Eq is an alternative to the standard Java equals method.
It is defined by the single method eqv:

scala
def eqv(x: A, y: A): Boolean

In Scala it's possible to compare any two values using == (which desugars to Java equals).
This is because equals type signature uses Any (Java's Object) to compare two values.
This means that we can compare two completely unrelated types without getting a compiler error.
The Scala compiler may warn us in some cases, but not all, which can lead to some weird bugs.
For example this code will raise a warning at compile time:

scala mdoc:warn
42 == "Hello"

While this code will compile without a hitch:

scala mdoc
"Hello" == 42

Ideally, Scala shouldn't let us compare two types that can never be equal.

As you can probably see in the type signature of eqv, it is impossible to compare two values of different types,
eliminating these types of bugs altogether.

The Eq syntax package also offers some handy symbolic operators:

scala mdoc
import cats.syntax.all._

1 === 1

"Hello" =!= "World"

Implementing Eq instances yourself for every data type might seem like huge drawback compared to only slight gains of typesafety.
Fortunately for us, we have two great options. One option is to use inbuilt helper functions.
Another option is to use a small library called kittens, which can derive a lot of type class instances for our data types including Eq.

The first option using Eq.fromUniversalEquals only defers to == and works like this:

scala mdoc
import cats.kernel.Eq
import cats.syntax.all._


case class Foo(a: Int, b: String)


implicit val eqFoo: Eq[Foo] = Eq.fromUniversalEquals


Foo(10, "") === Foo(10, "")

For an example using Kittens check out the kittens repo.


Typeclasses Foldable (`docs/typeclasses/foldable.md`)

Foldable

API Documentation: @:api(cats.Foldable)

Foldable type class instances can be defined for data structures that can be
folded to a summary value.

In the case of a collection (such as List or Vector), these methods will fold
together (combine) the values contained in the collection to produce a single
result. Most collection types have foldLeft methods, which will usually be
used by the associated Foldable[_] instance.

Foldable[F] is implemented in terms of two basic methods:

  • foldLeft(fa, b)(f) eagerly performs a left-associative fold over fa.
  • foldRight(fa, b)(f) lazily performs a right-associative fold over fa.

Consider a simple list like List(1, 2, 3). You could sum the numbers of this list using folds
where 0 is the starting value (b) and integer addition (+) is the combination operation
(f). Since foldLeft is left-associative, the execution of this fold would look something like
((0 + 1) + 2) + 3. The execution of a similar foldRight-based solution would look something
like 0 + (1 + (2 + 3)). In this case, since integer addition is associative, both approaches will
yield the same result. However, for non-associative operations, the two methods can produce
different results.

These form the basis for many other operations, see also:
A tutorial on the universality and expressiveness of fold

First some standard imports.

scala mdoc:silent
import cats._
import cats.syntax.all._

And examples.

text
/* Detailed source-code truncated for AI context efficiency. */

Hence when defining some new data structure, if we can define a foldLeft and
foldRight we are able to provide many other useful operations, if not always
the most efficient implementations, over the structure without further
implementation.


Note that, in order to support laziness, the signature of Foldable's
foldRight is

scala
def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B]

as opposed to

scala
def foldRight[A, B](fa: F[A], z: B)(f: (A, B) => B): B

which someone familiar with the foldRight from the collections in
Scala's standard library might expect. This will prevent operations
which are lazy in their right hand argument to traverse the entire
structure unnecessarily. For example, if you have:

scala mdoc
val allFalse = LazyList.continually(false)

which is an infinite list of false values, and if you wanted to
reduce this to a single false value using the logical and (&&). You
intuitively know that the result of this operation should be
false. It is not necessary to consider the entire list in order to
determine this result, you only need to consider the first
value. Using foldRight from the standard library will try to
consider the entire list, and thus will eventually cause an out-of-memory error:

scala
// beware! throws OutOfMemoryError, which is irrecoverable
allFalse.foldRight(true)(_ && _)

With the lazy foldRight on Foldable, the calculation terminates
after looking at only one value:

scala mdoc
Foldable[LazyList].foldRight(allFalse, Eval.True)((a,b) => if (a) b else Eval.False).value

Unfortunately, since foldRight is defined on many collections - this
extension clashes with the operation defined in Foldable.
To get past this and make sure you're getting the lazy foldRight defined
in Foldable, there's an alias foldr:

scala mdoc
allFalse.foldr(Eval.True)((a,b) => if (a) b else Eval.False).value

Typeclasses Functor (`docs/typeclasses/functor.md`)

Functor

API Documentation: @:api(cats.Functor)

Functor is a type class that abstracts over type constructors that can be map'ed over. Examples of such
type constructors are List, Option, and Future.

scala mdoc:silent
trait Functor[F[_]] {
  def map[A, B](fa: F[A])(f: A => B): F[B]
}

// Example implementation for Option
implicit val functorForOption: Functor[Option] = new Functor[Option] {
  def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa match {
    case None    => None
    case Some(a) => Some(f(a))
  }
}

A Functor instance must obey two laws:

  • Composition: Mapping with f and then again with g is the same as mapping once with the composition of f and g

    • fa.map(f).map(g) = fa.map(f.andThen(g))
  • Identity: Mapping with the identity function is a no-op

    • fa.map(x => x) = fa

A different view

Another way of viewing a Functor[F] is that F allows the lifting of a pure function A => B into the effectful
function F[A] => F[B]. We can see this if we re-order the map signature above.

scala mdoc:silent:nest
trait Functor[F[_]] {
  def map[A, B](fa: F[A])(f: A => B): F[B]

  def lift[A, B](f: A => B): F[A] => F[B] =
    fa => map(fa)(f)
}

Functors for effect management

The F in Functor is often referred to as an "effect" or "computational context." Different effects will
abstract away different behaviors with respect to fundamental functions like map. For instance, Option's effect
abstracts away potentially missing values, where map applies the function only in the Some case but
otherwise threads the None through.

Taking this view, we can view Functor as the ability to work with a single effect - we can apply a pure
function to a single effectful value without needing to "leave" the effect.

Functors compose

If you've ever found yourself working with nested data types such as Option[List[A]] or
List[Either[String, Future[A]]] and tried to map over it, you've most likely found yourself doing something
like _.map(_.map(_.map(f))). As it turns out, Functors compose, which means if F and G have
Functor instances, then so does F[G[_]].

Such composition can be achieved via the Functor#compose method.

scala mdoc:reset:silent
import cats.Functor
import cats.syntax.all._
scala mdoc
val listOption = List(Some(1), None, Some(2))

// Through Functor#compose
Functor[List].compose[Option].map(listOption)(_ + 1)

This approach will allow us to use composition without wrapping the value in question, but can
introduce complications in more complex use cases. For example, if we need to call another function which
requires a Functor and we want to use the composed Functor, we would have to explicitly pass in the
composed instance during the function call or create a local implicit.

scala mdoc:silent
def needsFunctor[F[_]: Functor, A](fa: F[A]): F[Unit] = Functor[F].map(fa)(_ => ())

def foo: List[Option[Unit]] = {
  val listOptionFunctor = Functor[List].compose[Option]
  type ListOption[A] = List[Option[A]]
  needsFunctor[ListOption, Int](listOption)(listOptionFunctor)
}

We can make this nicer at the cost of boxing with the Nested data type.

scala mdoc:silent
import cats.data.Nested
import cats.syntax.all._
scala mdoc
val nested: Nested[List, Option, Int] = Nested(listOption)

nested.map(_ + 1)

The Nested approach, being a distinct type from its constituents, will resolve the usual way modulo
possible SI-2712 issues (which can be addressed through partial unification),
but requires syntactic and runtime overhead from wrapping and unwrapping.


Typeclasses Invariant (`docs/typeclasses/invariant.md`)

Invariant

API Documentation: @:api(cats.Invariant)

The Invariant type class is for functors that define an imap
function with the following type:

scala
def imap[A, B](fa: F[A])(f: A => B)(g: B => A): F[B]

Every covariant (as well as contravariant) functor gives rise to an invariant
functor, by ignoring the g (or in case of contravariance, f) function.

Examples for instances of Invariant are Semigroup and Monoid, in
the following we will explain why this is the case using Semigroup, the
reasoning for Monoid is analogous.

Invariant instance for Semigroup

Pretend that we have a Semigroup[Long] representing a standard UNIX
timestamp. Let's say that we want to create a Semigroup[Date], by
reusing Semigroup[Long].

Semigroup does not form a covariant functor

If Semigroup had an instance for the standard covariant Functor
type class, we could use map to apply a function longToDate:

scala mdoc:silent
import java.util.Date
def longToDate: Long => Date = new Date(_)

But is this enough to give us a Semigroup[Date]? The answer is no,
unfortunately. A Semigroup[Date] should be able to combine two
values of type Date, given a Semigroup that only knows how to
combine Longs! The longToDate function does not help at all,
because it only allows us to convert a Long into a Date. Seems
like we can't have an Functor instance for Semigroup.

Semigroup does not form a contravariant functor

On the other side, if Semigroup would form a contravariant functor
by having an instance for Contravariant, we could make use of
contramap to apply a function dateToLong:

scala mdoc:silent
import java.util.Date
def dateToLong: Date => Long = _.getTime

Again we are faced with a problem when trying to get a
Semigroup[Date] based on a Semigroup[Long]. As before consider
the case where we have two values of Date at hand. Using
dateToLong we can turn them into Longs and use Semigroup[Long]
to combine the two values. We are left with a value of type Long,
but we can't turn it back into a Date using only contramap!

Semigroup does form an invariant functor

From the previous discussion we conclude that we need both the map
from (covariant) Functor and contramap from Contravariant.
There already is a type class for this and it is called Invariant.
Instances of the Invariant type class provide the imap function:

scala
def imap[A, B](fa: F[A])(f: A => B)(g: B => A): F[B]

Reusing the example of turning Semigroup[Long] into
Semigroup[Date], we can use the g parameter to turn Date into a
Long, combine our two values using Semigroup[Long] and then
convert the result back into a Date using the f parameter of
imap:

scala mdoc:silent:reset
import java.util.Date

// import everything for simplicity:
import cats._
import cats.syntax.all._

def longToDate: Long => Date = new Date(_)
def dateToLong: Date => Long = _.getTime

implicit val semigroupDate: Semigroup[Date] =
  Semigroup[Long].imap(longToDate)(dateToLong)

val today: Date = longToDate(1449088684104l)
val timeLeft: Date = longToDate(1900918893l)
scala mdoc
today |+| timeLeft

Typeclasses Invariantmonoidal (`docs/typeclasses/invariantmonoidal.md`)

Invariant Monoidal

API Documentation: @:api(cats.InvariantMonoidal)

InvariantMonoidal combines Invariant and Semigroupal with the addition of a unit methods, defined in isolation the InvariantMonoidal type class could be defined as follows:

scala mdoc:compile-only
trait InvariantMonoidal[F[_]] {
  def unit: F[Unit]
  def imap[A, B](fa: F[A])(f: A => B)(g: B => A): F[B]
  def product[A, B](fa: F[A], fb: F[B]): F[(A, B)]
}

Practical uses of InvariantMonoidal appear in the context of codecs, that is interfaces to capture both serialization and deserialization for a given format. Another notable examples is Semigroup.

This tutorial first shows how Semigroup is InvariantMonoidal, and how this can be used create Semigroup instances by combining other Semigroup instances. Secondly, we present a complete example of Codec for the CSV format, and show how it is InvariantMonoidal. Lastly, we present an alternative definition of InvariantMonoidal as a generalization of Invariant, and show that both definitions are equivalent.

`Semigroup` is `InvariantMonoidal`

As explained in the Invariant tutorial, Semigroup forms an invariant functor. Indeed, given a Semigroup[A] and two functions A => B and B => A, one can construct a Semigroup[B] by transforming two values from type B to type A, combining these using the Semigroup[A], and transforming the result back to type B. Thus to define an InvariantMonoidal[Semigroup] we need implementations for unit and product.

To construct a Semigroup from a single value, we can define a trivial Semigroup with a combine that always outputs the given value. A Semigroup[(A, B)] can be obtained from two Semigroups for type A and B by deconstructing two pairs into elements of type A and B, combining these element using their respective Semigroups, and reconstructing a pair from the results:

scala mdoc:silent
import cats.Semigroup

def unit: Semigroup[Unit] = (_, _) => ()

def product[A, B](fa: Semigroup[A], fb: Semigroup[B]): Semigroup[(A, B)] = {
  case ((xa, xb), (ya, yb)) => fa.combine(xa, ya) -> fb.combine(xb, yb)
}

Given an instance of InvariantMonoidal for Semigroup, we are able to combine existing Semigroup instances to form a new Semigroup by using the Semigroupal syntax:

scala mdoc:silent
import cats.syntax.all._

// Let's build a Semigroup for this case class
case class Foo(a: String, c: List[Double])

implicit val fooSemigroup: Semigroup[Foo] = (
  (implicitly[Semigroup[String]], implicitly[Semigroup[List[Double]]])
    .imapN(Foo.apply)(Function.unlift(Foo.unapply))
)

Our new Semigroup in action:

scala mdoc
Foo("Hello", List(0.0)) |+| Foo("World", Nil) |+| Foo("!", List(1.1, 2.2))

`CsvCodec` is `InvariantMonoidal`

We define CsvCodec, a type class for serialization and deserialization of CSV rows:

scala mdoc:silent
type CSV = List[String]

trait CsvCodec[A] {
  def read(s: CSV): (Option[A], CSV)
  def write(a: A): CSV
}

The read method consumes columns from a CSV row and returns an optional value and the remaining CSV. The write method produces the CSV representation of a given value.

Beside the composition capabilities illustrated later in this tutorial, grouping both serialization and deserialization in a single type class has the advantage to allows the definition of a law to capture the fact that both operations play nicely together:

scala
forAll { (c: CsvCodec[A], a: A) => c.read(c.write(a)) == ((Some(a), List()))

Let's now see how we could define an InvariantMonoidal instance for CsvCodec. Lifting a single value into a CsvCodec can be done "the trivial way" by consuming nothing from CSV and producing that value, and writing this value as the empty CSV:

scala mdoc:silent
trait CCUnit {
  def unit: CsvCodec[Unit] = new CsvCodec[Unit] {
    def read(s: CSV): (Option[Unit], CSV) = (Some(()), s)
    def write(u: Unit): CSV = List.empty
  }
}

Combining two CsvCodecs could be done by reading and writing each value of a pair sequentially, where reading succeeds if both read operations succeed:

scala mdoc:silent
trait CCProduct {
  def product[A, B](fa: CsvCodec[A], fb: CsvCodec[B]): CsvCodec[(A, B)] =
    new CsvCodec[(A, B)] {
      def read(s: CSV): (Option[(A, B)], CSV) = {
        val (a1, s1) = fa.read(s)
        val (a2, s2) = fb.read(s1)
        ((a1, a2).mapN(_ -> _), s2)
      }

      def write(a: (A, B)): CSV =
        fa.write(a._1) ++ fb.write(a._2)
    }
}

Changing a CsvCodec[A] to CsvCodec[B] requires two functions of type A => B and B => A to transform a value from A to B after deserialized, and from B to A before serialization:

scala mdoc:silent
trait CCImap {
  def imap[A, B](fa: CsvCodec[A])(f: A => B)(g: B => A): CsvCodec[B] =
    new CsvCodec[B] {
      def read(s: CSV): (Option[B], CSV) = {
        val (a1, s1) = fa.read(s)
        (a1.map(f), s1)
      }

      def write(a: B): CSV =
        fa.write(g(a))
    }
}

Putting it all together:

scala mdoc:silent
import cats.InvariantMonoidal

implicit val csvCodecIsInvariantMonoidal: InvariantMonoidal[CsvCodec] =
  new InvariantMonoidal[CsvCodec] with CCUnit with CCProduct with CCImap

We can now define a few CsvCodec instances and use the methods provided by InvariantMonoidal to define CsvCodec from existing CsvCodecs:

scala mdoc:silent
val stringCodec: CsvCodec[String] =
  new CsvCodec[String] {
    def read(s: CSV): (Option[String], CSV) = (s.headOption, s.drop(1))
    def write(a: String): CSV = List(a)
  }

def numericSystemCodec(base: Int): CsvCodec[Int] =
  new CsvCodec[Int] {
    def read(s: CSV): (Option[Int], CSV) =
      (s.headOption.flatMap(head => scala.util.Try(Integer.parseInt(head, base)).toOption), s.drop(1))

    def write(a: Int): CSV =
      List(Integer.toString(a, base))
  }
scala mdoc:silent:nest
case class BinDec(binary: Int, decimal: Int)

val binDecCodec: CsvCodec[BinDec] = (
  (numericSystemCodec(2), numericSystemCodec(10))
    .imapN(BinDec.apply)(Function.unlift(BinDec.unapply))
)

case class Foo(name: String, bd1: BinDec, bd2: BinDec)

val fooCodec: CsvCodec[Foo] = (
  (stringCodec, binDecCodec, binDecCodec)
    .imapN(Foo.apply)(Function.unlift(Foo.unapply))
)

Finally let's verify out CsvCodec law with an example:

scala mdoc
val foo = Foo("foo", BinDec(10, 10), BinDec(20, 20))

val fooCsv = fooCodec.write(foo)

fooCodec.read(fooCsv)

fooCodec.read(fooCodec.write(foo)) == ((Some(foo), List()))

`InvariantMonoidal` as a generalization of `Invariant`

To better understand the motivations behind the InvariantMonoidal type class, we show how one could naturally arrive to its definition by generalizing the concept of Invariant functor. This reflection is analogous to the one presented in Free Applicative Functors by Paolo Capriotti to show how Applicative are a generalization of Functor.

Given an Invariant[F] instance for a certain context F[_], its imap method gives a way to lift two unary pure functions A => B and B => A into contextualized functions F[A] => F[B]. But what about functions of other arity?

For instance, a value a of type A can be seen as a pair of nullary functions, one than given no input returns a, and the other than give a return no output, which we might want to lift them into a contextualized F[A]. Similarly, given two functions of type (A, B) => C and C => (A, B), we might want to contextualize them as functions of type (F[A], F[B]) => F[C].

The Invariant instance alone does not provide either of these lifting, and it is therefore natural to define define a type class for generalizing Invariants for functions of arbitrary arity:

scala mdoc:silent
trait MultiInvariant[F[_]] {
  def imap0[A](a: A): F[A]
  def imap1[A, B](f: A => B)(g: B => A)(fa: F[A]): F[B]
  def imap2[A, B, C](f: ((A, B)) => C)(g: C => (A, B))(fa: F[A], fb: F[B]): F[C]
}

Higher-arity imapN can be defined in terms of imap2, for example for N = 3:

scala mdoc:silent
trait MultiInvariantImap3[F[_]] extends MultiInvariant[F] {
  def imap3[A, B, C, D](
    f: ((A, B, C)) => D,
    g: D => (A, B, C),
    fa: F[A],
    fb: F[B],
    fc: F[C]
  ): F[D] = (
    imap2[A, (B, C), D]
      (f compose { case (a, (b, c)) => (a, b, c) })
      (g andThen { case (a, b, c) => (a, (b, c)) })
      (fa, imap2[B, C, (B, C)](identity)(identity)(fb, fc))
  )
}

We can observe that MultiInvariant is none other than an alternative formulation for InvariantMonoidal. Indeed, imap1 and imap only differ by the order of their argument, and imap2 can easily be defined in terms of imap and product:

scala mdoc:silent
trait Imap2FromImapProduct[F[_]] extends cats.InvariantMonoidal[F] {
  def imap2[A, B, C](f: ((A, B)) => C)(g: C => (A, B))(fa: F[A], fb: F[B]): F[C] =
    imap(product(fa, fb))(f)(g)
}

Typeclasses Lawtesting (`docs/typeclasses/lawtesting.md`)

Law testing

Laws are an important part of cats.
Cats uses discipline to define type class laws and
the ScalaCheck tests based on them.

To test type class laws from Cats against your instances, you need to add a cats-laws dependency.

Getting started

First up, you will need to specify dependencies on cats-laws in your build.sbt file.

scala
libraryDependencies ++= Seq(
  "org.typelevel" %% "cats-laws" % "@VERSION@" % Test,
)

Example: Testing a Functor instance

We'll begin by creating a data type and its Functor instance.

scala mdoc
import cats._

sealed trait Tree[+A]
case object Leaf extends Tree[Nothing]
case class Node[A](p: A, left: Tree[A], right: Tree[A]) extends Tree[A]

object Tree {
  implicit val functorTree: Functor[Tree] = new Functor[Tree] {
    def map[A, B](tree: Tree[A])(f: A => B) = tree match {
      case Leaf => Leaf
      case Node(p, left, right) => Node(f(p), map(left)(f), map(right)(f))
    }
  }
}
scala mdoc:invisible
import Tree._ //there is no real companion object in REPL

Cats defines all type class laws tests in cats.laws.discipline.*
as discipline's RuleSets. Each RuleSet provides a ScalaCheck Properties through
ruleSet.all to represent all the rules that it defines and inherits. For example,
the ScalaCheck Properties for Functor can be retrieved using

scala
cats.laws.discipline.FunctorTests[Tree].functor[Int, Int, String].all

We will also need to create an Eq instance, as most laws will need to compare values of a type to properly test for correctness.
For simplicity we'll just use Eq.fromUniversalEquals:

scala mdoc
implicit def eqTree[A: Eq]: Eq[Tree[A]] = Eq.fromUniversalEquals

ScalaCheck requires Arbitrary instances for data types being tested. We have defined an Arbitrary instance for Tree here,
if you use Scala 2, you can avoid writing it manually with scalacheck-shapeless.

scala mdoc:silent
import org.scalacheck.{Arbitrary, Gen}

object arbitraries {
  implicit def arbTree[A: Arbitrary]: Arbitrary[Tree[A]] =
    Arbitrary(Gen.oneOf(Gen.const(Leaf), (for {
      e <- Arbitrary.arbitrary[A]
    } yield Node(e, Leaf, Leaf)))
  )
}

Now we can convert these ScalaCheck Properties into tests that the test framework can run. discipline provides a helper checkAll function that performs
this conversion for three test frameworks: ScalaTest, Specs2 and MUnit.

  • If you are using Specs2, extend your test class with org.typelevel.discipline.specs2.Discipline (provided by discipline-specs2).

  • If you are using ScalaTest, extend your test class with org.typelevel.discipline.scalatest.FunSuiteDiscipline (provided by discipline-scalatest) and org.scalatest.funsuite.AnyFunSuiteLike.

  • If you are using MUnit, extend your test class with munit.DisciplineSuite (provided by discipline-munit).

  • For other test frameworks, you need to resort to their integration with ScalaCheck to test
    the ScalaCheck Properties provided by cats-laws.

The following example is for MUnit.

scala mdoc
import cats.syntax.all._
import cats.laws.discipline.FunctorTests
import munit.DisciplineSuite
import arbitraries._

class TreeLawTests extends DisciplineSuite {
  checkAll("Tree.FunctorLaws", FunctorTests[Tree].functor[Int, Int, String])
}
  • cats.implicits._ imports the instances we need for Eq[Tree[Int]], which the laws use to compare trees.
  • FunctorTests contains the functor laws.
  • AnyFunSuite defines the style of ScalaTest.
  • FunSuiteDiscipline provides checkAll, and must be mixed into AnyFunSuite
  • arbitraries._ imports the Arbitrary[Tree[_]] instances needed to check the laws.

Now when we run test in our sbt console, ScalaCheck will test if the Functor laws hold for our Tree type.
You should see something like this:

text
[info] TreeLawTests:
[info] - Tree.FunctorLaws.functor.covariant composition (58 milliseconds)
[info] - Tree.FunctorLaws.functor.covariant identity (3 milliseconds)
[info] - Tree.FunctorLaws.functor.invariant composition (19 milliseconds)
[info] - Tree.FunctorLaws.functor.invariant identity (3 milliseconds)
[info] Passed: Total 4, Failed 0, Errors 0, Passed 4
[success] Total time: 2 s, completed Aug 2, 2019 12:01:17 AM

And voila, you've successfully proven that your data type upholds the Functor laws!

Testing `cats.kernel` instances

For most of the type classes included in Cats, the above will work great.
However, the law tests for the type classes inside cats.kernel are located in cats.kernel.laws.discipline.* instead.
So we have to import from there to test type classes like Semigroup, Monoid, Group or Semilattice.

Let's test it out by defining a Semigroup instance for our Tree type.

scala mdoc
import cats.syntax.all._

implicit def semigroupTree[A: Semigroup]: Semigroup[Tree[A]] = new Semigroup[Tree[A]] {
  def combine(x: Tree[A], y: Tree[A]) = (x, y) match {
    case (Leaf, _) => Leaf
    case (_, Leaf) => Leaf
    case (Node(xp, xLeft, xRight), Node(yp, yLeft, yRight)) =>
      Node(xp |+| yp, combine(xLeft, yLeft), combine(xRight, yRight))
  }
}

Then we can add the Semigroup tests to our suite:

scala mdoc:nest
import cats.syntax.all._
import cats.kernel.laws.discipline.SemigroupTests
import cats.laws.discipline.FunctorTests
import munit.DisciplineSuite
import arbitraries._

class TreeLawTests extends DisciplineSuite {
  checkAll("Tree.FunctorLaws", FunctorTests[Tree].functor[Int, Int, String])
  checkAll("Tree[Int].SemigroupLaws", SemigroupTests[Tree[Int]].semigroup)
}

Typeclasses Monad (`docs/typeclasses/monad.md`)

Monad

API Documentation: @:api(cats.Monad)

Monad extends the Applicative type class with a
new function flatten. Flatten takes a value in a nested context (eg.
F[F[A]] where F is the context) and "joins" the contexts together so
that we have a single context (ie. F[A]).

The name flatten should remind you of the functions of the same name on many
classes in the standard library.

scala mdoc
Option(Option(1)).flatten
Option(None).flatten
List(List(1),List(2,3)).flatten

Monad instances

If Applicative is already present and flatten is well-behaved,
extending the Applicative to a Monad is trivial. To provide evidence
that a type belongs in the Monad type class, cats' implementation
requires us to provide an implementation of pure (which can be reused
from Applicative) and flatMap.

We can use flatten to define flatMap: flatMap is just map
followed by flatten. Conversely, flatten is just flatMap using
the identity function x => x (i.e. flatMap(_)(x => x)).

scala mdoc:silent
import cats._

implicit def optionMonad(implicit app: Applicative[Option]): Monad[Option] =
  new Monad[Option] {
    // Define flatMap using Option's flatten method
    override def flatMap[A, B](fa: Option[A])(f: A => Option[B]): Option[B] =
      app.map(fa)(f).flatten
    // Reuse this definition from Applicative.
    override def pure[A](a: A): Option[A] = app.pure(a)

    @annotation.tailrec
    def tailRecM[A, B](init: A)(fn: A => Option[Either[A, B]]): Option[B] =
      fn(init) match {
        case None => None
        case Some(Right(b)) => Some(b)
        case Some(Left(a)) => tailRecM(a)(fn)
      }
  }

flatMap

flatMap is often considered to be the core function of Monad, and Cats
follows this tradition by providing implementations of flatten and map
derived from flatMap and pure.

Part of the reason for this is that name flatMap has special significance in
scala, as for-comprehensions rely on this method to chain together operations
in a monadic context.

scala mdoc
import scala.reflect.runtime.universe

universe.reify(
  for {
    x <- Some(1)
    y <- Some(2)
  } yield x + y
).tree

tailRecM

In addition to requiring flatMap and pure, Cats has chosen to require
tailRecM which encodes stack safe monadic recursion, as described in
Stack Safety for Free by
Phil Freeman. Because monadic recursion is so common in functional programming but
is not stack safe on the JVM, Cats has chosen to require this method of all monad implementations
as opposed to just a subset. All functions requiring monadic recursion in Cats do so via
tailRecM.

An example Monad implementation for Option is shown below. Note the tail recursive
and therefore stack safe implementation of tailRecM.

scala mdoc:silent:reset
import cats.Monad
import scala.annotation.tailrec

implicit val optionMonad: Monad[Option] = new Monad[Option] {
  def flatMap[A, B](fa: Option[A])(f: A => Option[B]): Option[B] = fa.flatMap(f)
  def pure[A](a: A): Option[A] = Some(a)

  @tailrec
  def tailRecM[A, B](a: A)(f: A => Option[Either[A, B]]): Option[B] = f(a) match {
    case None              => None
    case Some(Left(nextA)) => tailRecM(nextA)(f) // continue the recursion
    case Some(Right(b))    => Some(b)            // recursion done
  }
}

More discussion about tailRecM can be found in the FAQ.

ifM

Monad provides the ability to choose later operations in a sequence based on
the results of earlier ones. This is embodied in ifM, which lifts an if
statement into the monadic context.

scala mdoc
import cats.syntax.all._

Monad[List].ifM(List(true, false, true))(ifTrue = List(1, 2), ifFalse = List(3, 4))

Composition

Unlike Functors and Applicatives,
not all Monads compose. This means that even if M[_] and N[_] are
both Monads, M[N[_]] is not guaranteed to be a Monad.

However, many common cases do. One way of expressing this is to provide
instructions on how to compose any outer monad (F in the following
example) with a specific inner monad (Option in the following
example).

Note: the example below assumes usage of the kind-projector compiler plugin and will not compile if it is not being used in a project.

scala mdoc:silent:reset
import cats.Monad
import cats.syntax.all._

case class OptionT[F[_], A](value: F[Option[A]])

implicit def optionTMonad[F[_]](implicit F: Monad[F]): Monad[OptionT[F, *]] = {
  new Monad[OptionT[F, *]] {
    def pure[A](a: A): OptionT[F, A] = OptionT(F.pure(Some(a)))
    def flatMap[A, B](fa: OptionT[F, A])(f: A => OptionT[F, B]): OptionT[F, B] =
      OptionT {
        F.flatMap(fa.value) {
          case None => F.pure(None)
          case Some(a) => f(a).value
        }
      }

    def tailRecM[A, B](a: A)(f: A => OptionT[F, Either[A, B]]): OptionT[F, B] =
      OptionT {
        F.tailRecM(a)(a0 => F.map(f(a0).value) {
          case None => Either.right[A, Option[B]](None)
          case Some(b0) => b0.map(Some(_))
        })
      }
  }
}

This sort of construction is called a monad transformer.

Cats has an OptionT monad transformer, which adds a lot of useful functions to the simple implementation above.

FlatMap - a weakened Monad

A closely related type class is FlatMap which is identical to Monad, minus the pure
method. Indeed in Cats Monad is a subclass of FlatMap (from which it gets flatMap)
and Applicative (from which it gets pure).

scala
trait FlatMap[F[_]] extends Apply[F] {
  def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
}

trait Monad[F[_]] extends FlatMap[F] with Applicative[F]

The laws for FlatMap are just the laws of Monad that don't mention pure.

One of the motivations for FlatMap's existence is that some types have FlatMap instances but not
Monad - one example is Map[K, *]. Consider the behavior of pure for Map[K, A]. Given
a value of type A, we need to associate some arbitrary K to it but we have no way of doing that.

However, given existing Map[K, A] and Map[K, B] (or Map[K, A => B]), it is straightforward to
pair up (or apply functions to) values with the same key. Hence Map[K, *] has an FlatMap instance.


Typeclasses Monoid (`docs/typeclasses/monoid.md`)

Monoid

API Documentation: @:api(cats.kernel.Monoid)

Monoid extends the power of Semigroup by providing an additional empty value.

scala mdoc:silent
trait Semigroup[A] {
  def combine(x: A, y: A): A
}

trait Monoid[A] extends Semigroup[A] {
  def empty: A
}

This empty value should be an identity for the combine operation, which means the following equalities hold
for any choice of x.

text
combine(x, empty) = combine(empty, x) = x

Many types that form a Semigroup also form a Monoid, such as Ints (with 0) and Strings (with "").

scala mdoc:reset:silent
import cats.Monoid

implicit val intAdditionMonoid: Monoid[Int] = new Monoid[Int] {
  def empty: Int = 0
  def combine(x: Int, y: Int): Int = x + y
}

val x = 1
scala mdoc
Monoid[Int].combine(x, Monoid[Int].empty)

Monoid[Int].combine(Monoid[Int].empty, x)

Example usage: Collapsing a list

In the Semigroup section we had trouble writing a generic combineAll function because we had nothing
to give if the list was empty. With Monoid we can return empty, giving us

scala mdoc:silent
def combineAll[A: Monoid](as: List[A]): A =
  as.foldLeft(Monoid[A].empty)(Monoid[A].combine)

which can be used for any type that has a Monoid instance.

scala mdoc:silent
import cats.syntax.all._
scala mdoc
combineAll(List(1, 2, 3))

combineAll(List("hello", " ", "world"))

combineAll(List(Map('a' -> 1), Map('a' -> 2, 'b' -> 3), Map('b' -> 4, 'c' -> 5)))

combineAll(List(Set(1, 2), Set(2, 3, 4, 5)))

This function is provided in Cats as Monoid.combineAll.

The `Option` monoid

There are some types that can form a Semigroup but not a Monoid. For example, the
following NonEmptyList type forms a semigroup through ++, but has no corresponding
identity element to form a monoid.

scala mdoc:silent
import cats.Semigroup

final case class NonEmptyList[A](head: A, tail: List[A]) {
  def ++(other: NonEmptyList[A]): NonEmptyList[A] = NonEmptyList(head, tail ++ other.toList)

  def toList: List[A] = head :: tail
}

object NonEmptyList {
  implicit def nonEmptyListSemigroup[A]: Semigroup[NonEmptyList[A]] = _ ++ _
}

How then can we collapse a List[NonEmptyList[A]] ? For such types that only have a Semigroup we can
lift into Option to get a Monoid.

scala mdoc:silent
import cats.syntax.all._

implicit def optionMonoid[A: Semigroup]: Monoid[Option[A]] = new Monoid[Option[A]] {
  def empty: Option[A] = None

  def combine(x: Option[A], y: Option[A]): Option[A] =
    x match {
      case None => y
      case Some(xv) =>
        y match {
          case None => x
          case Some(yv) => Some(xv |+| yv)
        }
    }
}

This is the Monoid for Option: for any Semigroup[A], there is a Monoid[Option[A]].

Thus:

scala mdoc:reset:silent
import cats.Monoid
import cats.data.NonEmptyList
import cats.syntax.all._

val list = List(NonEmptyList(1, List(2, 3)), NonEmptyList(4, List(5, 6)))
val lifted = list.map(nel => Option(nel))
scala mdoc
Monoid.combineAll(lifted)

This lifting and combining of Semigroups into Option is provided by Cats as Semigroup.combineAllOption.


N.B.
Cats defines the Monoid type class in cats-kernel. The
cats package object
defines type aliases to the Monoid from cats-kernel, so that you can simply import cats.Monoid.


Typeclasses Monoidk (`docs/typeclasses/monoidk.md`)

MonoidK

API Documentation: @:api(cats.MonoidK)

MonoidK is a universal monoid which operates on type constructors of one argument.

This type class is useful when its type parameter F[_] has a
structure that can be combined for any particular type, and which
also has an "empty" representation. Thus, MonoidK is like a Monoid
for type constructors (i.e. parametrized types).

A MonoidK[F] can produce a Monoid[F[A]] for any type A.

Here's how to distinguish Monoid and MonoidK:

  • Monoid[A] allows A values to be combined, and also means there
    is an "empty" A value that functions as an identity.

  • MonoidK[F] allows two F[A] values to be combined, for any A. It
    also means that for any A, there is an "empty" F[A] value. The
    combination operation and empty value just depend on the
    structure of F, but not on the structure of A.

Let's compare the usage of Monoid[A] and MonoidK[F].

First some imports:

scala mdoc:silent
import cats.{Monoid, MonoidK}
import cats.syntax.all._

Just like Monoid[A], MonoidK[F] has an empty method, but it is parametrized on the type of the element contained in F:

scala mdoc
Monoid[List[String]].empty
MonoidK[List].empty[String]
MonoidK[List].empty[Int]

And instead of combine, it has combineK, which also takes one type parameter:

scala mdoc
Monoid[List[String]].combine(List("hello", "world"), List("goodbye", "moon"))
MonoidK[List].combineK[String](List("hello", "world"), List("goodbye", "moon"))
MonoidK[List].combineK[Int](List(1, 2), List(3, 4))

Actually the type parameter can usually be inferred:

scala mdoc
MonoidK[List].combineK(List("hello", "world"), List("goodbye", "moon"))
MonoidK[List].combineK(List(1, 2), List(3, 4))

MonoidK extends SemigroupK, so take a look at the SemigroupK documentation for more examples.


Typeclasses Nonemptytraverse (`docs/typeclasses/nonemptytraverse.md`)

NonEmptyTraverse

API Documentation: @:api(cats.NonEmptyTraverse)

NonEmptyTraverse is a non-empty version of the Traverse type class, just like Reducible is a non-empty version of Foldable.
As such, it extends both Reducible and Traverse in the type class hierarchy.
It provides the nonEmptyTraverse and nonEmptySequence methods that require an instance of Apply instead of Applicative:

scala
def nonEmptyTraverse[G[_]: Apply, A, B](fa: F[A])(f: A => G[B]): G[F[B]]

def nonEmptySequence[G[_]: Apply, A](fga: F[G[A]]): G[F[A]]

In the Applicative tutorial we learned of Apply as a weakened Applicative lacking the pure method.
One example type lacking an Applicative instance is Map[K, *], it's impossible to implement a pure method for it.

Knowing this, we can make use of NonEmptyTraverse, to traverse over a sequence of Maps.
One example application one could think of is, when we have a list of text snippets,
count the occurrence of each word in each snippet and return all the common words and their occurrences in each snippet:

scala mdoc
import cats.syntax.all._
import cats.data.NonEmptyList

val snippets = NonEmptyList.of("What do you do", "What are you doing")

def countWords(text: String): Map[String, Int] =
  text.split(" ").groupBy(identity).view.mapValues(_.length).toMap

snippets.nonEmptyTraverse(countWords)

Note that, just like traverse, nonEmptyTraverse(f) is equivalent to map(f).nonEmptySequence, so the above could be rewritten as:

scala mdoc
snippets.map(countWords).nonEmptySequence

NonEmptyTraverse also offers flatNonEmptyTraverse and flatNonEmptySequence methods that are analogous to flatTraverse and flatSequence in Traverse.
Just like with nonEmptyTraverse these methods don't require a Monad instance, but only a FlatMap, which is the weakened version of Monad without pure.


Typeclasses Parallel (`docs/typeclasses/parallel.md`)

Parallel

API Documentation: @:api(cats.Parallel)

When browsing the various Monads included in Cats,
you may have noticed that some of them have data types that are actually of the same structure,
but instead have instances of Applicative. E.g. Either and Validated.

This is because defining a Monad instance for data types like Validated would be inconsistent with its error-accumulating behaviour.
In short, Monads describe dependent computations and Applicatives describe independent computations.

Sometimes however, we want to use both in conjunction with each other.
In the example of Either and Validated it is trivial albeit cumbersome to convert between the two types.
Below is a short example of a situation where we might run into this.
For simplicity, we'll use String as our type to represent errors.

scala mdoc
import cats.syntax.all._
import cats.data._

case class Name(value: String)
case class Age(value: Int)
case class Person(name: Name, age: Age)

def parse(s: String): Either[NonEmptyList[String], Int] = {
  if (s.matches("-?[0-9]+")) Right(s.toInt)
  else Left(NonEmptyList.one(s"$s is not a valid integer."))
}

def validateAge(a: Int): Either[NonEmptyList[String], Age] = {
  if (a > 18) Right(Age(a))
  else Left(NonEmptyList.one(s"$a is not old enough"))
}

def validateName(n: String): Either[NonEmptyList[String], Name] = {
  if (n.length >= 8) Right(Name(n))
  else Left(NonEmptyList.one(s"$n Does not have enough characters"))
}

Now we want to parse two Strings into a value of Person:

scala mdoc
def parsePerson(ageString: String, nameString: String) =
  for {
    age <- parse(ageString)
    person <- (validateName(nameString).toValidated, validateAge(age).toValidated)
       .mapN(Person)
       .toEither
  } yield person

We had to convert to and from Validated manually.
While this is still manageble, it gets worse the more Eithers we want to combine in parallel.

To mitigate this pain, Cats introduces a type class Parallel that abstracts over Monads which also support parallel composition.
It is simply defined in terms of conversion functions between the two data types:

scala
trait Parallel[M[_]] {
  type F[_]

  def sequential: F ~> M

  def parallel: M ~> F
}

Where M[_] has to have an instance of Monad and F[_] an instance of Applicative.

Recall that ~> is just an alias for FunctionK.
This allows us to get rid of most of our boilerplate from earlier:

scala mdoc:nest
def parsePerson(ageString: String, nameString: String) =
  for {
    age <- parse(ageString)
    person <- (validateName(nameString), validateAge(age)).parMapN(Person)
  } yield person

We can also traverse over a Traverse using Parallel:

scala mdoc
List(Either.right(42), Either.left(NonEmptyList.one("Error 1")), Either.left(NonEmptyList.one("Error 2"))).parSequence

Parallel is also really useful for zipping collections. The standard Applicative instance for List, Vector, etc.
behaves like the cartesian product of the individual collections:

scala mdoc
(List(1, 2, 3), List(4, 5, 6)).mapN(_ + _)

However often we will want to zip two or more collections together.
We can define a different ap for most of them and use the parMapN syntax for that:

scala mdoc
(List(1, 2, 3), List(4, 5, 6)).parMapN(_ + _)

NonEmptyParallel - a weakened Parallel

Some types cannot form a Monad or an Applicative because it's not possible to implement the pure function for them.
However, these types can often have instances for FlatMap or Apply.
For types like these we can use the NonEmptyParallel type class.
An example for one of these is ZipList.

With instances of NonEmptyParallel it's not possible to use the parTraverse and parSequence functions,
but we can still use parMapN and also parNonEmptyTraverse and parNonEmptySequence,
which are analogous to the functions defined on NonEmptyTraverse.


Typeclasses Reducible (`docs/typeclasses/reducible.md`)

Reducible

API Documentation: @:api(cats.Reducible)

Reducible extends the Foldable type class with additional reduce methods.

You may have come by one of the reduce, reduceLeft or reduceOption defined in Scala's standard collections.
Reducible offers exactly these methods with the guarantee that the collection won't throw an exception due to a collection being empty, without having to reduce to an Option.
This can be utilized effectively to derive maximum and minimum methods from Reducible instead of the maximumOption and minimumOption found on Foldable.

In essence, reduce is like a non-empty fold, requiring no initial value.
This makes Reducible very useful for abstracting over non-empty collections such as NonEmptyList or NonEmptyVector.

Analogous to the Foldable type class, Reducible[F] is implemented in terms of two basic methods in addition to those required by Foldable:

  • reduceLeftTo(fa)(f)(g) eagerly reduces with an additional mapping function
  • reduceRightTo(fa)(f)(g) lazily reduces with an additional mapping function

Now, because Reducible does not require an empty value, the equivalent of fold and foldMap, reduce and reduceMap, do not require an instance of Monoid, but of Semigroup.

Furthermore, just like with foldRight, reduceRight uses the Eval data type to lazily reduce the collection.

First some standard imports.

scala mdoc:silent
import cats._
import cats.data._
import cats.syntax.all._

And examples.

scala mdoc
Reducible[NonEmptyList].reduce(NonEmptyList.of("a", "b", "c"))
Reducible[NonEmptyList].reduceMap(NonEmptyList.of(1, 2, 4))(_.toString)
Reducible[NonEmptyVector].reduceK(NonEmptyVector.of(List(1,2,3), List(2,3,4)))
Reducible[NonEmptyVector].reduceLeft(NonEmptyVector.of(1,2,3,4))((s,i) => s + i)
Reducible[NonEmptyList].reduceRight(NonEmptyList.of(1,2,3,4))((i,s) => Later(s.value + i)).value
Reducible[NonEmptyList].reduceLeftTo(NonEmptyList.of(1,2,3,4))(_.toString)((s,i) => s + i)
Reducible[NonEmptyList].reduceRightTo(NonEmptyList.of(1,2,3,4))(_.toString)((i,s) => Later(s.value + i)).value
Reducible[NonEmptyList].nonEmptyIntercalate(NonEmptyList.of("a", "b", "c"), ", ")

def countChars(s: String) = s.toCharArray.groupBy(identity).view.mapValues(_.length).toMap

Reducible[NonEmptyList].nonEmptyTraverse_(NonEmptyList.of("Hello", "World"))(countChars)
Reducible[NonEmptyVector].nonEmptyTraverse_(NonEmptyVector.of("Hello", ""))(countChars)
Reducible[NonEmptyList].nonEmptySequence_(NonEmptyList.of(Map(1 -> 'o'), Map(1 -> 'o')))

In addition to reduce requiring a Semigroup instead of a Monoid, nonEmptyTraverse_ and nonEmptySequence_ require Apply instead of Applicative.
Also, Reducible offers a reduceLeftM method, that is just like foldM, but requires a FlatMap instance of a Monad instance.

scala
def reduceLeftM[G[_]: FlatMap, A, B](fa: F[A])(f: A => G[B])(g: (B, A) => G[B]): G[B]

Typeclasses Semigroup (`docs/typeclasses/semigroup.md`)

Semigroup

API Documentation: @:api(cats.kernel.Semigroup)

If a type A can form a Semigroup it has an associative binary operation.

scala mdoc:silent
trait Semigroup[A] {
  def combine(x: A, y: A): A
}

Associativity means the following equality must hold for any choice of x, y, and
z.

text
combine(x, combine(y, z)) = combine(combine(x, y), z)

A common example of a semigroup is the type Int with the operation +.

scala mdoc:reset:silent
import cats.Semigroup

implicit val intAdditionSemigroup: Semigroup[Int] = _ + _

val x = 1
val y = 2
val z = 3
scala mdoc
Semigroup[Int].combine(x, y)

Semigroup[Int].combine(x, Semigroup[Int].combine(y, z))

Semigroup[Int].combine(Semigroup[Int].combine(x, y), z)

Infix syntax is also available for types that have a Semigroup instance.

scala mdoc
import cats.syntax.all._

1 |+| 2

A more compelling example which we'll see later in this tutorial is the Semigroup
for Maps.

scala mdoc:silent
import cats.syntax.all._

val map1 = Map("hello" -> 1, "world" -> 1)
val map2 = Map("hello" -> 2, "cats"  -> 3)
scala mdoc
Semigroup[Map[String, Int]].combine(map1, map2)

map1 |+| map2

Example instances

Cats provides many Semigroup instances out of the box such as Int (+) and String (++)...

scala mdoc:reset:silent
import cats.Semigroup
import cats.syntax.all._
scala mdoc
Semigroup[Int]
Semigroup[String]

Instances for type constructors regardless of their type parameter such as List (++)
and Set (union)...

scala mdoc
Semigroup[List[Byte]]
Semigroup[Set[Int]]

trait Foo
Semigroup[List[Foo]]

And instances for type constructors that depend on (one of) their type parameters having instances such
as tuples (pointwise combine).

scala mdoc
Semigroup[(List[Foo], Int)]

Example usage: Merging maps

Consider a function that merges two Maps that combines values if they share
the same key. It is straightforward to write these for Maps with values of
type say, Int or List[String], but we can write it once and for all for
any type with a Semigroup instance.

scala mdoc:silent
import cats.syntax.all._

def optionCombine[A: Semigroup](a: A, opt: Option[A]): A =
  opt.map(a |+| _).getOrElse(a)

def mergeMap[K, V: Semigroup](lhs: Map[K, V], rhs: Map[K, V]): Map[K, V] =
  lhs.foldLeft(rhs) {
    case (acc, (k, v)) => acc.updated(k, optionCombine(v, acc.get(k)))
  }
scala mdoc
val xm1 = Map('a' -> 1, 'b' -> 2)
val xm2 = Map('b' -> 3, 'c' -> 4)

val x = mergeMap(xm1, xm2)

val ym1 = Map(1 -> List("hello"))
val ym2 = Map(2 -> List("cats"), 1 -> List("world"))

val y = mergeMap(ym1, ym2)

It is interesting to note that the type of mergeMap satisfies the type of Semigroup
specialized to Map[K, *] and is associative - indeed the Semigroup instance for Map
uses the same function for its combine.

scala mdoc
Semigroup[Map[Char, Int]].combine(xm1, xm2) == x

Semigroup[Map[Int, List[String]]].combine(ym1, ym2) == y

Exploiting laws: associativity

Since we know Semigroup#combine must be associative, we can exploit this when writing
code against Semigroup. For instance, to sum a List[Int] we can choose to either
foldLeft or foldRight since all that changes is associativity.

scala mdoc
val leftwards = List(1, 2, 3).foldLeft(0)(_ |+| _)

val rightwards = List(1, 2, 3).foldRight(0)(_ |+| _)

Associativity also allows us to split a list apart and sum the parts in parallel, gathering the results in
the end.

scala mdoc:silent
val list = List(1, 2, 3, 4, 5)
val (left, right) = list.splitAt(2)
scala mdoc
val sumLeft = left.foldLeft(0)(_ |+| _)
val sumRight = right.foldLeft(0)(_ |+| _)
val result = sumLeft |+| sumRight

However, given just Semigroup we cannot write the above expressions generically. For instance, we quickly
run into issues if we try to write a generic combineAll function.

scala
def combineAll[A: Semigroup](as: List[A]): A =
  as.foldLeft(/* ?? what goes here ?? */)(_ |+| _)

Semigroup isn't powerful enough for us to implement this function - namely, it doesn't give us an identity
or fallback value if the list is empty. We need a more powerfully expressive abstraction, which we can find in the
Monoid type class.

N.B.
Cats defines the Semigroup type class in cats-kernel. The
cats package object
defines type aliases to the Semigroup from cats-kernel, so that you can simply import cats.Semigroup.


Typeclasses Semigroupk (`docs/typeclasses/semigroupk.md`)

SemigroupK

API Documentation: @:api(cats.SemigroupK)

SemigroupK has a very similar structure to Semigroup, the difference
is that SemigroupK operates on type constructors of one argument. So, for
example, whereas you can find a Semigroup for types which are fully
specified like Int or List[Int] or Option[Int], you will find
SemigroupK for type constructors like List and Option. These types
are type constructors in that you can think of them as "functions" in
the type space. You can think of the List type as a function which
takes a concrete type, like Int, and returns a concrete type:
List[Int]. This pattern would also be referred to having kind: * -> *, whereas Int would have kind * and Map would have kind *,* -> *,
and, in fact, the K in SemigroupK stands for Kind.

First some imports.

scala mdoc:silent
import cats._
import cats.syntax.all._

For List, the Semigroup instance's combine operation and the SemigroupK
instance's combineK operation are both list concatenation:

scala mdoc
SemigroupK[List].combineK(List(1,2,3), List(4,5,6)) == Semigroup[List[Int]].combine(List(1,2,3), List(4,5,6))

However for Option, the Semigroup's combine and the SemigroupK's
combineK operation differ. Since Semigroup operates on fully specified
types, a Semigroup[Option[A]] knows the concrete type of A and will use
Semigroup[A].combine to combine the inner As. Consequently,
Semigroup[Option[A]].combine requires an implicit Semigroup[A].

In contrast, SemigroupK[Option] operates on Option where
the inner type is not fully specified and can be anything (i.e. is
"universally quantified"). Thus, we cannot know how to combine
two of them. Therefore, in the case of Option the
SemigroupK[Option].combineK method has no choice but to use the
orElse method of Option:

scala mdoc
Semigroup[Option[Int]].combine(Some(1), Some(2))
SemigroupK[Option].combineK(Some(1), Some(2))
SemigroupK[Option].combineK(Some(1), None)
SemigroupK[Option].combineK(None, Some(2))

There is inline syntax available for both Semigroup and
SemigroupK. Here we are following the convention from scalaz, that
|+| is the operator from semigroup and that <+> is the operator
from SemigroupK (called Plus in scalaz).

scala mdoc:silent
import cats.syntax.all._

val one = Option(1)
val two = Option(2)
val n: Option[Int] = None

Thus.

scala mdoc
one |+| two
one <+> two
n |+| two
n <+> two
n |+| n
n <+> n
two |+| n
two <+> n

You'll notice that instead of declaring one as Some(1), we chose
Option(1), and we added an explicit type declaration for n. This is
because the SemigroupK type class instances is defined for Option,
not Some or None. If we try to use Some or None, we'll get errors:

scala mdoc:fail
Some(1) <+> None
None <+> Some(1)

Typeclasses Show (`docs/typeclasses/show.md`)

Show

API Documentation: @:api(cats.Show)

Show is an alternative to the Java toString method.
It is defined by a single function show:

scala
def show(a: A):