High-performance, asynchronous, composable framework for building purely functional applications with the IO monad and effect system
npx @tessl/cli install tessl/maven-org-typelevel--cats-effect_2-12@3.6.0Cats Effect is a high-performance, asynchronous, composable framework for building real-world applications in a purely functional style within the Typelevel ecosystem. It provides a concrete tool, known as 'the IO monad', for capturing and controlling actions, often referred to as 'effects', that your program wishes to perform within a resource-safe, typed context with seamless support for concurrency and coordination.
libraryDependencies += "org.typelevel" %% "cats-effect" % "3.6.1"import cats.effect._
import cats.effect.implicits._For kernel-only (minimal dependencies):
import cats.effect.kernel._For standard library implementations:
import cats.effect.std._import cats.effect._
object MyApp extends IOApp {
def run(args: List[String]): IO[ExitCode] = {
for {
_ <- IO.println("Hello, Cats Effect!")
// Create a concurrent reference
ref <- Ref.of[IO, Int](0)
// Start concurrent fibers
fiber1 <- (ref.update(_ + 1) >> IO.sleep(100.millis)).start
fiber2 <- (ref.update(_ + 10) >> IO.sleep(50.millis)).start
// Wait for both to complete
_ <- fiber1.join.void
_ <- fiber2.join.void
// Read final value
result <- ref.get
_ <- IO.println(s"Final value: $result")
// Resource management example
_ <- Resource.make(IO.println("Acquiring resource"))(_ => IO.println("Releasing resource"))
.use(_ => IO.println("Using resource"))
} yield ExitCode.Success
}
}Cats Effect is built around several key architectural components:
Resource and bracket operationsThe library follows the typeclass pattern from category theory, providing increasingly powerful abstractions:
Functor < Applicative < Monad < MonadError < MonadCancel < Spawn < Concurrent < Temporal < Async
The IO monad and essential operations for building purely functional applications. Includes basic IO operations, error handling, and composition.
// IO construction and basic operations
def IO.pure[A](value: A): IO[A]
def IO.delay[A](thunk: => A): IO[A]
def IO.blocking[A](thunk: => A): IO[A]
def IO.async[A](k: (Either[Throwable, A] => Unit) => IO[Option[IO[Unit]]]): IO[A]
// Error handling
def attempt: IO[Either[Throwable, A]]
def handleErrorWith[AA >: A](f: Throwable => IO[AA]): IO[AA]
def guarantee(finalizer: IO[Unit]): IO[A]
// Composition
def flatMap[B](f: A => IO[B]): IO[B]
def map[B](f: A => B): IO[B]Fiber-based concurrency with structured concurrency patterns. Provides fiber spawning, coordination, and cancellation.
// Fiber operations
def start: IO[Fiber[IO, Throwable, A]]
def race[B](other: IO[B]): IO[Either[A, B]]
def both[B](other: IO[B]): IO[(A, B)]
def background: Resource[IO, IO[Outcome[IO, Throwable, A]]]
// Coordination primitives
def Ref.of[F[_], A](initial: A): F[Ref[F, A]]
def Deferred[F[_], A]: F[Deferred[F, A]]Safe resource acquisition, usage, and cleanup with the Resource data type and bracket patterns.
sealed abstract class Resource[F[_], +A] {
def use[B](f: A => F[B]): F[B]
def allocated: F[(A, F[Unit])]
def map[B](f: A => B): Resource[F, B]
def flatMap[B](f: A => Resource[F, B]): Resource[F, B]
}
def Resource.make[F[_], A](acquire: F[A])(release: A => F[Unit]): Resource[F, A]
def bracket[A, B](acquire: F[A])(use: A => F[B])(release: A => F[Unit]): F[B]Time-based operations including delays, timeouts, and scheduling.
def IO.sleep(duration: Duration): IO[Unit]
def timeout(duration: Duration): IO[A]
def timeoutTo[AA >: A](duration: Duration, fallback: IO[AA]): IO[AA]
def delayBy(duration: Duration): IO[A]
def timed: IO[(Duration, A)]Standard implementations of common concurrent data structures and system integration.
// Queues
abstract class Queue[F[_], A] {
def offer(a: A): F[Unit]
def take: F[A]
def size: F[Int]
}
// Synchronization
abstract class Semaphore[F[_]] {
def acquire: F[Unit]
def release: F[Unit]
def withPermit[A](fa: F[A]): F[A]
}
// System integration
trait Console[F[_]] {
def println(line: Any): F[Unit]
def readLine: F[String]
}Runtime configuration, unsafe operations, and application patterns.
final class IORuntime {
def unsafeRunSync[A](io: IO[A]): A
def unsafeRunAsync[A](io: IO[A])(cb: Either[Throwable, A] => Unit): Unit
def shutdown(): Unit
}
trait IOApp {
def run(args: List[String]): IO[ExitCode]
}// Primary effect types
sealed abstract class IO[+A]
sealed abstract class SyncIO[+A]
sealed abstract class Resource[F[_], +A]
// Coordination primitives
abstract class Ref[F[_], A] {
def get: F[A]
def set(a: A): F[Unit]
def modify[B](f: A => (A, B)): F[B]
}
abstract class Deferred[F[_], A] {
def get: F[A]
def complete(a: A): F[Unit]
}
// Fiber execution results
sealed trait Outcome[F[_], E, A]
final case class Succeeded[F[_], E, A](fa: F[A]) extends Outcome[F, E, A]
final case class Errored[F[_], E, A](e: E) extends Outcome[F, E, A]
final case class Canceled[F[_], E, A]() extends Outcome[F, E, A]
// Fiber handles
trait Fiber[F[_], E, A] {
def cancel: F[Unit]
def join: F[Outcome[F, E, A]]
}type OutcomeIO[A] = Outcome[IO, Throwable, A]
type FiberIO[A] = Fiber[IO, Throwable, A]
type ResourceIO[A] = Resource[IO, A]