or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

core-type-classes.mddata-types.mderror-handling.mdindex.mdinstances.mdmonad-transformers.mdsyntax-extensions.md
tile.json

tessl/maven-org-typelevel--cats-core_3

Cats-core provides essential abstractions and type classes for functional programming in Scala including Functor, Monad, Applicative, and many others.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/org.typelevel/cats-core_3@2.13.x

To install, run

npx @tessl/cli install tessl/maven-org-typelevel--cats-core_3@2.13.0

index.mddocs/

Cats Core - Functional Programming Library for Scala

Cats-core is the foundational functional programming library for Scala that provides essential abstractions and type classes for safe, composable, and expressive functional programming. It includes fundamental type classes like Functor, Monad, and Applicative, along with powerful data types and monad transformers.

Package Information

Package: cats-core
Version: 2.13.0
Organization: org.typelevel

Installation

// SBT
libraryDependencies += "org.typelevel" %% "cats-core" % "2.13.0"

// Mill
ivy"org.typelevel::cats-core:2.13.0"

// Maven
<dependency>
    <groupId>org.typelevel</groupId>
    <artifactId>cats-core_3</artifactId>
    <version>2.13.0</version>
</dependency>

Core Imports

Quick Start - Import Everything

import cats.implicits._
// Imports all syntax extensions and type class instances
// Most convenient for general usage

// Example usage after import
val result = List(1, 2, 3).map(_ + 1)  // List(2, 3, 4)
val combined = (Option(1), Option(2)).mapN(_ + _)  // Some(3)

Import Strategies

// All syntax extensions only
import cats.syntax.all._

// All type class instances only  
import cats.instances.all._

// Specific type classes
import cats.{Functor, Applicative, Monad}
import cats.syntax.functor._
import cats.syntax.applicative._

// Specific data types
import cats.data.{NonEmptyList, Validated, EitherT}
import cats.data.Validated.{Valid, Invalid}

// Kernel types (re-exported from cats.kernel)
import cats.{Eq, Order, Semigroup, Monoid}  // Available directly from cats package
// Or import from kernel directly:
// import cats.kernel.{Eq, Order, Semigroup, Monoid}

// Instances for specific standard library types
import cats.instances.list._
import cats.instances.option._
import cats.instances.either._

Type Class Summoning

import cats.Functor
import cats.syntax.functor._

// Summon type class instances
val listFunctor = Functor[List]
val optionFunctor = Functor[Option]

// Use summoned instances
listFunctor.map(List(1, 2, 3))(_ * 2)  // List(2, 4, 6)

// Or use syntax extensions directly
List(1, 2, 3).map(_ * 2)  // List(2, 4, 6)

Basic Usage

Functor - Transform Values in Context

import cats.syntax.functor._

// Transform values inside containers
List(1, 2, 3).map(_ + 1)           // List(2, 3, 4)
Option(5).map(_ * 2)               // Some(10)
Right(10).map(_.toString)          // Right("10")

// Chain transformations
List("hello", "world")
  .map(_.toUpperCase)
  .map(_.length)                   // List(5, 5)

Applicative - Combine Independent Effects

import cats.syntax.applicative._
import cats.syntax.apply._

// Lift pure values
42.pure[Option]                    // Some(42)
"hello".pure[List]                 // List("hello")

// Combine multiple wrapped values
(Option(1), Option(2), Option(3)).mapN(_ + _ + _)    // Some(6)
(List(1, 2), List(10, 20)).mapN(_ + _)              // List(11, 21, 12, 22)

// Product of values
(Option("hello"), Option(42)).tupled               // Some(("hello", 42))

Monad - Sequential Dependent Computations

import cats.syntax.flatMap._
import cats.syntax.functor._

// Chain dependent computations
def divide(a: Int, b: Int): Option[Double] = 
  if (b != 0) Some(a.toDouble / b) else None

for {
  x <- Some(10)
  y <- Some(2) 
  result <- divide(x, y)
} yield result                     // Some(5.0)

// Equivalent with flatMap/map
Some(10).flatMap(x => 
  Some(2).flatMap(y => 
    divide(x, y)))                 // Some(5.0)

Error Handling with Validated

import cats.data.Validated
import cats.data.Validated.{Valid, Invalid}
import cats.syntax.apply._

type ValidationResult[A] = Validated[List[String], A]

def validateName(name: String): ValidationResult[String] = 
  if (name.nonEmpty) Valid(name) 
  else Invalid(List("Name cannot be empty"))

def validateAge(age: Int): ValidationResult[Int] = 
  if (age >= 0) Valid(age) 
  else Invalid(List("Age must be positive"))

// Accumulate all validation errors
case class Person(name: String, age: Int)

val result = (validateName(""), validateAge(-5)).mapN(Person.apply)
// Invalid(List("Name cannot be empty", "Age must be positive"))

Architecture

Cats-core is organized around a hierarchy of type classes that build upon each other:

Functor[F[_]]
                         |
                     Apply[F[_]]
                         |
                  Applicative[F[_]]
                         |
                    FlatMap[F[_]]
                         |
                     Monad[F[_]]
                         |
              ApplicativeError[F[_], E]
                         |
                MonadError[F[_], E]

Core Packages

  • cats - Fundamental type classes (Functor, Monad, etc.)
  • cats.data - Data types and monad transformers
  • cats.syntax - Extension methods for type classes
  • cats.instances - Type class instances for standard library types
  • cats.arrow - Arrow type classes for function-like types

Core Type Classes

Essential abstractions for functional programming patterns.

Functor Hierarchy

import cats.{Functor, Apply, Applicative, FlatMap, Monad}

// Functor - map over wrapped values
trait Functor[F[_]] {
  def map[A, B](fa: F[A])(f: A => B): F[B]
}

// Apply - apply wrapped functions to wrapped values  
trait Apply[F[_]] extends Functor[F] {
  def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
  def map2[A, B, Z](fa: F[A], fb: F[B])(f: (A, B) => Z): F[Z]
}

// Applicative - lift pure values + Apply
trait Applicative[F[_]] extends Apply[F] {
  def pure[A](x: A): F[A]
}

// FlatMap - monadic bind operation
trait FlatMap[F[_]] extends Apply[F] {
  def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
}

// Monad - combines Applicative + FlatMap  
trait Monad[F[_]] extends Applicative[F] with FlatMap[F]

See Core Type Classes for complete API documentation.

Error Handling

import cats.{ApplicativeError, MonadError}

// Error handling for Applicative
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 attempt[A](fa: F[A]): F[Either[E, A]]
}

// Error handling for Monad
trait MonadError[F[_], E] extends ApplicativeError[F, E] with Monad[F] {
  def ensure[A](fa: F[A])(error: => E)(predicate: A => Boolean): F[A]
}

// Common type aliases
type ApplicativeThrow[F[_]] = ApplicativeError[F, Throwable]
type MonadThrow[F[_]] = MonadError[F, Throwable]

See Error Handling for patterns and examples.

Traversable Structures

import cats.{Foldable, Traverse}

// Fold structures to summary values
trait Foldable[F[_]] {
  def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): B
  def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B]
  def foldMap[A, B](fa: F[A])(f: A => B)(implicit B: Monoid[B]): B
}

// Traverse with effects
trait Traverse[F[_]] extends Foldable[F] with Functor[F] {
  def traverse[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Applicative[G]): G[F[B]]
  def sequence[G[_], A](fga: F[G[A]])(implicit G: Applicative[G]): G[F[A]]
}

Data Types

Essential data types for functional programming.

Non-Empty Collections

import cats.data.{NonEmptyList, NonEmptyChain}

// Lists guaranteed to have at least one element
val nel = NonEmptyList.of(1, 2, 3)              // NonEmptyList[Int]
val single = NonEmptyList.one(42)               // NonEmptyList[Int]
val fromList = NonEmptyList.fromList(List(1, 2)) // Option[NonEmptyList[Int]]

// Efficient append/prepend chains
val nec = NonEmptyChain.of("a", "b", "c")        // NonEmptyChain[String]  
val appended = nec.append("d")                   // O(1) operation

Validated Data Types

import cats.data.{Validated, Ior}
import cats.data.Validated.{Valid, Invalid}

// Error accumulation
val validation: Validated[String, Int] = Valid(42)
val error: Validated[String, Int] = Invalid("Error message")

// Inclusive OR - can have left, right, or both
val left = Ior.Left("warning")                   // Ior[String, Int]
val right = Ior.Right(42)                        // Ior[String, Int]  
val both = Ior.Both("warning", 42)               // Ior[String, Int]

See Data Types for comprehensive coverage of all data types.

Monad Transformers

Stack multiple monadic effects together.

Option and Either Transformers

import cats.data.{OptionT, EitherT}
import cats.effect.IO

// Stack Option with IO
type AsyncOption[A] = OptionT[IO, A]

val computation: AsyncOption[String] = for {
  user <- OptionT(getUserById(userId))           // IO[Option[User]]  
  profile <- OptionT(getProfile(user.id))       // IO[Option[Profile]]
} yield profile.displayName                     // AsyncOption[String]

// Stack Either with IO for error handling
type AsyncResult[A] = EitherT[IO, String, A]

val result: AsyncResult[User] = for {
  input <- EitherT(validateInput(data))         // IO[Either[String, Input]]
  user <- EitherT(createUser(input))            // IO[Either[String, User]]  
} yield user                                    // AsyncResult[User]

State and Reader Transformers

import cats.data.{StateT, ReaderT}

// Stateful computations
type GameState[A] = StateT[IO, GameWorld, A]

val gameLoop: GameState[Unit] = for {
  world <- StateT.get[IO, GameWorld]            // Get current state
  _ <- StateT.modify[IO, GameWorld](updatePhysics) // Modify state
  _ <- StateT.liftF(renderFrame(world))         // Lift IO into StateT
} yield ()

// Dependency injection pattern
type App[A] = ReaderT[IO, AppConfig, A]

val application: App[String] = for {
  config <- ReaderT.ask[IO, AppConfig]          // Access environment
  result <- ReaderT.liftF(processWithConfig(config)) // Lift IO
} yield result

See Monad Transformers for detailed transformer usage.

Syntax Extensions

Extension methods that make type class operations available as natural method calls.

Functor and Applicative Syntax

import cats.syntax.functor._
import cats.syntax.applicative._
import cats.syntax.apply._

// Functor operations  
List(1, 2, 3).map(_ * 2)                       // List(2, 4, 6)
List(1, 2, 3).as("x")                          // List("x", "x", "x")  
List(1, 2, 3).void                             // List((), (), ())

// Applicative operations
42.pure[List]                                   // List(42)
(List(1, 2), List(10, 20)).mapN(_ + _)         // List(11, 21, 12, 22)
(List(1), List(2)).tupled                      // List((1, 2))

// Apply sequencing
List(1, 2) <* List("a", "b")                   // List(1, 1, 2, 2) 
List(1, 2) *> List("a", "b")                   // List("a", "b", "a", "b")

Monad and Traverse Syntax

import cats.syntax.flatMap._
import cats.syntax.traverse._

// Monad operations
List(1, 2).flatMap(x => List(x, x * 10))       // List(1, 10, 2, 20)
List(1, 2) >> List("a", "b")                   // List("a", "b", "a", "b")

// Traverse operations  
List(1, 2, 3).traverse(x => Option(x))         // Some(List(1, 2, 3))
List(Some(1), Some(2), Some(3)).sequence       // Some(List(1, 2, 3))

See Syntax Extensions for all available syntax.

Type Class Instances

Pre-built instances for Scala standard library types.

Standard Collections

import cats.instances.list._
import cats.instances.vector._  
import cats.instances.option._

// Lists have Monad, Traverse, Alternative
List(1, 2, 3).flatMap(x => List(x, -x))        // List(1, -1, 2, -2, 3, -3)

// Vectors have same instances as Lists
Vector(1, 2, 3).traverse(Option(_))            // Some(Vector(1, 2, 3))

// Option has Monad, Alternative, Traverse  
Option(1).flatMap(x => if (x > 0) Some(x * 2) else None) // Some(2)

Either and Try

import cats.instances.either._
import cats.instances.try_._

// Either has Monad in right projection
Right(10).flatMap(x => if (x > 5) Right(x * 2) else Left("too small")) // Right(20)

// Try has MonadError for exception handling
import scala.util.Try
Try(10 / 2).recover { case _: ArithmeticException => 0 } // Success(5)

See Instances for complete instance documentation.

Error Accumulation Patterns

Using Validated for Input Validation

import cats.data.ValidatedNec
import cats.syntax.validated._
import cats.syntax.apply._

// Validated with NonEmptyChain for error accumulation
type ValidationResult[A] = ValidatedNec[String, A]

case class User(name: String, email: String, age: Int)

def validateName(name: String): ValidationResult[String] =
  if (name.trim.nonEmpty) name.valid
  else "Name cannot be empty".invalidNec

def validateEmail(email: String): ValidationResult[String] =
  if (email.contains("@")) email.valid  
  else "Email must be valid".invalidNec

def validateAge(age: Int): ValidationResult[Int] =
  if (age >= 18) age.valid
  else "Must be 18 or older".invalidNec

// All errors collected together
val userValidation = (
  validateName(""),
  validateEmail("invalid"),  
  validateAge(16)
).mapN(User.apply)

// Invalid(Chain(Name cannot be empty, Email must be valid, Must be 18 or older))

Parallel Validation

import cats.syntax.parallel._

// Process validations in parallel for better performance
val parallelValidation = (
  validateName("John"),
  validateEmail("john@example.com"),
  validateAge(25)
).parMapN(User.apply)
// Valid(User("John", "john@example.com", 25))

Stack Safety

All Cats operations are stack-safe through careful implementation:

import cats.Eval

// Stack-safe recursive computation
def factorial(n: BigInt): Eval[BigInt] = {
  if (n <= 1) Eval.now(BigInt(1))
  else factorial(n - 1).map(_ * n)
}

val result = factorial(100000).value // Won't stack overflow

// Stack-safe traverse operations
val largeList = (1 to 100000).toList
val traversed = largeList.traverse(x => Eval.later(x * 2))
traversed.value // Safe computation

Next Steps

This introduction covers the fundamental concepts and common patterns. For detailed documentation on specific areas:

Each section provides comprehensive API documentation with practical examples for effective usage of cats-core in functional Scala programming.