Cats-core provides essential abstractions and type classes for functional programming in Scala including Functor, Monad, Applicative, and many others.
npx @tessl/cli install tessl/maven-org-typelevel--cats-core_3@2.13.00
# Cats Core - Functional Programming Library for Scala
1
2
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.
3
4
## Package Information
5
6
**Package**: `cats-core`
7
**Version**: `2.13.0`
8
**Organization**: `org.typelevel`
9
10
### Installation
11
12
```scala { .api }
13
// SBT
14
libraryDependencies += "org.typelevel" %% "cats-core" % "2.13.0"
15
16
// Mill
17
ivy"org.typelevel::cats-core:2.13.0"
18
19
// Maven
20
<dependency>
21
<groupId>org.typelevel</groupId>
22
<artifactId>cats-core_3</artifactId>
23
<version>2.13.0</version>
24
</dependency>
25
```
26
27
## Core Imports
28
29
### Quick Start - Import Everything
30
```scala { .api }
31
import cats.implicits._
32
// Imports all syntax extensions and type class instances
33
// Most convenient for general usage
34
35
// Example usage after import
36
val result = List(1, 2, 3).map(_ + 1) // List(2, 3, 4)
37
val combined = (Option(1), Option(2)).mapN(_ + _) // Some(3)
38
```
39
40
### Import Strategies
41
42
```scala { .api }
43
// All syntax extensions only
44
import cats.syntax.all._
45
46
// All type class instances only
47
import cats.instances.all._
48
49
// Specific type classes
50
import cats.{Functor, Applicative, Monad}
51
import cats.syntax.functor._
52
import cats.syntax.applicative._
53
54
// Specific data types
55
import cats.data.{NonEmptyList, Validated, EitherT}
56
import cats.data.Validated.{Valid, Invalid}
57
58
// Kernel types (re-exported from cats.kernel)
59
import cats.{Eq, Order, Semigroup, Monoid} // Available directly from cats package
60
// Or import from kernel directly:
61
// import cats.kernel.{Eq, Order, Semigroup, Monoid}
62
63
// Instances for specific standard library types
64
import cats.instances.list._
65
import cats.instances.option._
66
import cats.instances.either._
67
```
68
69
### Type Class Summoning
70
```scala { .api }
71
import cats.Functor
72
import cats.syntax.functor._
73
74
// Summon type class instances
75
val listFunctor = Functor[List]
76
val optionFunctor = Functor[Option]
77
78
// Use summoned instances
79
listFunctor.map(List(1, 2, 3))(_ * 2) // List(2, 4, 6)
80
81
// Or use syntax extensions directly
82
List(1, 2, 3).map(_ * 2) // List(2, 4, 6)
83
```
84
85
## Basic Usage
86
87
### Functor - Transform Values in Context
88
```scala { .api }
89
import cats.syntax.functor._
90
91
// Transform values inside containers
92
List(1, 2, 3).map(_ + 1) // List(2, 3, 4)
93
Option(5).map(_ * 2) // Some(10)
94
Right(10).map(_.toString) // Right("10")
95
96
// Chain transformations
97
List("hello", "world")
98
.map(_.toUpperCase)
99
.map(_.length) // List(5, 5)
100
```
101
102
### Applicative - Combine Independent Effects
103
```scala { .api }
104
import cats.syntax.applicative._
105
import cats.syntax.apply._
106
107
// Lift pure values
108
42.pure[Option] // Some(42)
109
"hello".pure[List] // List("hello")
110
111
// Combine multiple wrapped values
112
(Option(1), Option(2), Option(3)).mapN(_ + _ + _) // Some(6)
113
(List(1, 2), List(10, 20)).mapN(_ + _) // List(11, 21, 12, 22)
114
115
// Product of values
116
(Option("hello"), Option(42)).tupled // Some(("hello", 42))
117
```
118
119
### Monad - Sequential Dependent Computations
120
```scala { .api }
121
import cats.syntax.flatMap._
122
import cats.syntax.functor._
123
124
// Chain dependent computations
125
def divide(a: Int, b: Int): Option[Double] =
126
if (b != 0) Some(a.toDouble / b) else None
127
128
for {
129
x <- Some(10)
130
y <- Some(2)
131
result <- divide(x, y)
132
} yield result // Some(5.0)
133
134
// Equivalent with flatMap/map
135
Some(10).flatMap(x =>
136
Some(2).flatMap(y =>
137
divide(x, y))) // Some(5.0)
138
```
139
140
### Error Handling with Validated
141
```scala { .api }
142
import cats.data.Validated
143
import cats.data.Validated.{Valid, Invalid}
144
import cats.syntax.apply._
145
146
type ValidationResult[A] = Validated[List[String], A]
147
148
def validateName(name: String): ValidationResult[String] =
149
if (name.nonEmpty) Valid(name)
150
else Invalid(List("Name cannot be empty"))
151
152
def validateAge(age: Int): ValidationResult[Int] =
153
if (age >= 0) Valid(age)
154
else Invalid(List("Age must be positive"))
155
156
// Accumulate all validation errors
157
case class Person(name: String, age: Int)
158
159
val result = (validateName(""), validateAge(-5)).mapN(Person.apply)
160
// Invalid(List("Name cannot be empty", "Age must be positive"))
161
```
162
163
## Architecture
164
165
Cats-core is organized around a hierarchy of type classes that build upon each other:
166
167
```scala { .api }
168
Functor[F[_]]
169
|
170
Apply[F[_]]
171
|
172
Applicative[F[_]]
173
|
174
FlatMap[F[_]]
175
|
176
Monad[F[_]]
177
|
178
ApplicativeError[F[_], E]
179
|
180
MonadError[F[_], E]
181
```
182
183
### Core Packages
184
185
- **`cats`** - Fundamental type classes (Functor, Monad, etc.)
186
- **`cats.data`** - Data types and monad transformers
187
- **`cats.syntax`** - Extension methods for type classes
188
- **`cats.instances`** - Type class instances for standard library types
189
- **`cats.arrow`** - Arrow type classes for function-like types
190
191
## Core Type Classes
192
193
Essential abstractions for functional programming patterns.
194
195
### Functor Hierarchy
196
```scala { .api }
197
import cats.{Functor, Apply, Applicative, FlatMap, Monad}
198
199
// Functor - map over wrapped values
200
trait Functor[F[_]] {
201
def map[A, B](fa: F[A])(f: A => B): F[B]
202
}
203
204
// Apply - apply wrapped functions to wrapped values
205
trait Apply[F[_]] extends Functor[F] {
206
def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
207
def map2[A, B, Z](fa: F[A], fb: F[B])(f: (A, B) => Z): F[Z]
208
}
209
210
// Applicative - lift pure values + Apply
211
trait Applicative[F[_]] extends Apply[F] {
212
def pure[A](x: A): F[A]
213
}
214
215
// FlatMap - monadic bind operation
216
trait FlatMap[F[_]] extends Apply[F] {
217
def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
218
}
219
220
// Monad - combines Applicative + FlatMap
221
trait Monad[F[_]] extends Applicative[F] with FlatMap[F]
222
```
223
224
See [Core Type Classes](core-type-classes.md) for complete API documentation.
225
226
### Error Handling
227
```scala { .api }
228
import cats.{ApplicativeError, MonadError}
229
230
// Error handling for Applicative
231
trait ApplicativeError[F[_], E] extends Applicative[F] {
232
def raiseError[A](e: E): F[A]
233
def handleErrorWith[A](fa: F[A])(f: E => F[A]): F[A]
234
def attempt[A](fa: F[A]): F[Either[E, A]]
235
}
236
237
// Error handling for Monad
238
trait MonadError[F[_], E] extends ApplicativeError[F, E] with Monad[F] {
239
def ensure[A](fa: F[A])(error: => E)(predicate: A => Boolean): F[A]
240
}
241
242
// Common type aliases
243
type ApplicativeThrow[F[_]] = ApplicativeError[F, Throwable]
244
type MonadThrow[F[_]] = MonadError[F, Throwable]
245
```
246
247
See [Error Handling](error-handling.md) for patterns and examples.
248
249
### Traversable Structures
250
```scala { .api }
251
import cats.{Foldable, Traverse}
252
253
// Fold structures to summary values
254
trait Foldable[F[_]] {
255
def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): B
256
def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B]
257
def foldMap[A, B](fa: F[A])(f: A => B)(implicit B: Monoid[B]): B
258
}
259
260
// Traverse with effects
261
trait Traverse[F[_]] extends Foldable[F] with Functor[F] {
262
def traverse[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Applicative[G]): G[F[B]]
263
def sequence[G[_], A](fga: F[G[A]])(implicit G: Applicative[G]): G[F[A]]
264
}
265
```
266
267
## Data Types
268
269
Essential data types for functional programming.
270
271
### Non-Empty Collections
272
```scala { .api }
273
import cats.data.{NonEmptyList, NonEmptyChain}
274
275
// Lists guaranteed to have at least one element
276
val nel = NonEmptyList.of(1, 2, 3) // NonEmptyList[Int]
277
val single = NonEmptyList.one(42) // NonEmptyList[Int]
278
val fromList = NonEmptyList.fromList(List(1, 2)) // Option[NonEmptyList[Int]]
279
280
// Efficient append/prepend chains
281
val nec = NonEmptyChain.of("a", "b", "c") // NonEmptyChain[String]
282
val appended = nec.append("d") // O(1) operation
283
```
284
285
### Validated Data Types
286
```scala { .api }
287
import cats.data.{Validated, Ior}
288
import cats.data.Validated.{Valid, Invalid}
289
290
// Error accumulation
291
val validation: Validated[String, Int] = Valid(42)
292
val error: Validated[String, Int] = Invalid("Error message")
293
294
// Inclusive OR - can have left, right, or both
295
val left = Ior.Left("warning") // Ior[String, Int]
296
val right = Ior.Right(42) // Ior[String, Int]
297
val both = Ior.Both("warning", 42) // Ior[String, Int]
298
```
299
300
See [Data Types](data-types.md) for comprehensive coverage of all data types.
301
302
## Monad Transformers
303
304
Stack multiple monadic effects together.
305
306
### Option and Either Transformers
307
```scala { .api }
308
import cats.data.{OptionT, EitherT}
309
import cats.effect.IO
310
311
// Stack Option with IO
312
type AsyncOption[A] = OptionT[IO, A]
313
314
val computation: AsyncOption[String] = for {
315
user <- OptionT(getUserById(userId)) // IO[Option[User]]
316
profile <- OptionT(getProfile(user.id)) // IO[Option[Profile]]
317
} yield profile.displayName // AsyncOption[String]
318
319
// Stack Either with IO for error handling
320
type AsyncResult[A] = EitherT[IO, String, A]
321
322
val result: AsyncResult[User] = for {
323
input <- EitherT(validateInput(data)) // IO[Either[String, Input]]
324
user <- EitherT(createUser(input)) // IO[Either[String, User]]
325
} yield user // AsyncResult[User]
326
```
327
328
### State and Reader Transformers
329
```scala { .api }
330
import cats.data.{StateT, ReaderT}
331
332
// Stateful computations
333
type GameState[A] = StateT[IO, GameWorld, A]
334
335
val gameLoop: GameState[Unit] = for {
336
world <- StateT.get[IO, GameWorld] // Get current state
337
_ <- StateT.modify[IO, GameWorld](updatePhysics) // Modify state
338
_ <- StateT.liftF(renderFrame(world)) // Lift IO into StateT
339
} yield ()
340
341
// Dependency injection pattern
342
type App[A] = ReaderT[IO, AppConfig, A]
343
344
val application: App[String] = for {
345
config <- ReaderT.ask[IO, AppConfig] // Access environment
346
result <- ReaderT.liftF(processWithConfig(config)) // Lift IO
347
} yield result
348
```
349
350
See [Monad Transformers](monad-transformers.md) for detailed transformer usage.
351
352
## Syntax Extensions
353
354
Extension methods that make type class operations available as natural method calls.
355
356
### Functor and Applicative Syntax
357
```scala { .api }
358
import cats.syntax.functor._
359
import cats.syntax.applicative._
360
import cats.syntax.apply._
361
362
// Functor operations
363
List(1, 2, 3).map(_ * 2) // List(2, 4, 6)
364
List(1, 2, 3).as("x") // List("x", "x", "x")
365
List(1, 2, 3).void // List((), (), ())
366
367
// Applicative operations
368
42.pure[List] // List(42)
369
(List(1, 2), List(10, 20)).mapN(_ + _) // List(11, 21, 12, 22)
370
(List(1), List(2)).tupled // List((1, 2))
371
372
// Apply sequencing
373
List(1, 2) <* List("a", "b") // List(1, 1, 2, 2)
374
List(1, 2) *> List("a", "b") // List("a", "b", "a", "b")
375
```
376
377
### Monad and Traverse Syntax
378
```scala { .api }
379
import cats.syntax.flatMap._
380
import cats.syntax.traverse._
381
382
// Monad operations
383
List(1, 2).flatMap(x => List(x, x * 10)) // List(1, 10, 2, 20)
384
List(1, 2) >> List("a", "b") // List("a", "b", "a", "b")
385
386
// Traverse operations
387
List(1, 2, 3).traverse(x => Option(x)) // Some(List(1, 2, 3))
388
List(Some(1), Some(2), Some(3)).sequence // Some(List(1, 2, 3))
389
```
390
391
See [Syntax Extensions](syntax-extensions.md) for all available syntax.
392
393
## Type Class Instances
394
395
Pre-built instances for Scala standard library types.
396
397
### Standard Collections
398
```scala { .api }
399
import cats.instances.list._
400
import cats.instances.vector._
401
import cats.instances.option._
402
403
// Lists have Monad, Traverse, Alternative
404
List(1, 2, 3).flatMap(x => List(x, -x)) // List(1, -1, 2, -2, 3, -3)
405
406
// Vectors have same instances as Lists
407
Vector(1, 2, 3).traverse(Option(_)) // Some(Vector(1, 2, 3))
408
409
// Option has Monad, Alternative, Traverse
410
Option(1).flatMap(x => if (x > 0) Some(x * 2) else None) // Some(2)
411
```
412
413
### Either and Try
414
```scala { .api }
415
import cats.instances.either._
416
import cats.instances.try_._
417
418
// Either has Monad in right projection
419
Right(10).flatMap(x => if (x > 5) Right(x * 2) else Left("too small")) // Right(20)
420
421
// Try has MonadError for exception handling
422
import scala.util.Try
423
Try(10 / 2).recover { case _: ArithmeticException => 0 } // Success(5)
424
```
425
426
See [Instances](instances.md) for complete instance documentation.
427
428
## Error Accumulation Patterns
429
430
### Using Validated for Input Validation
431
```scala { .api }
432
import cats.data.ValidatedNec
433
import cats.syntax.validated._
434
import cats.syntax.apply._
435
436
// Validated with NonEmptyChain for error accumulation
437
type ValidationResult[A] = ValidatedNec[String, A]
438
439
case class User(name: String, email: String, age: Int)
440
441
def validateName(name: String): ValidationResult[String] =
442
if (name.trim.nonEmpty) name.valid
443
else "Name cannot be empty".invalidNec
444
445
def validateEmail(email: String): ValidationResult[String] =
446
if (email.contains("@")) email.valid
447
else "Email must be valid".invalidNec
448
449
def validateAge(age: Int): ValidationResult[Int] =
450
if (age >= 18) age.valid
451
else "Must be 18 or older".invalidNec
452
453
// All errors collected together
454
val userValidation = (
455
validateName(""),
456
validateEmail("invalid"),
457
validateAge(16)
458
).mapN(User.apply)
459
460
// Invalid(Chain(Name cannot be empty, Email must be valid, Must be 18 or older))
461
```
462
463
### Parallel Validation
464
```scala { .api }
465
import cats.syntax.parallel._
466
467
// Process validations in parallel for better performance
468
val parallelValidation = (
469
validateName("John"),
470
validateEmail("john@example.com"),
471
validateAge(25)
472
).parMapN(User.apply)
473
// Valid(User("John", "john@example.com", 25))
474
```
475
476
## Stack Safety
477
478
All Cats operations are stack-safe through careful implementation:
479
480
```scala { .api }
481
import cats.Eval
482
483
// Stack-safe recursive computation
484
def factorial(n: BigInt): Eval[BigInt] = {
485
if (n <= 1) Eval.now(BigInt(1))
486
else factorial(n - 1).map(_ * n)
487
}
488
489
val result = factorial(100000).value // Won't stack overflow
490
491
// Stack-safe traverse operations
492
val largeList = (1 to 100000).toList
493
val traversed = largeList.traverse(x => Eval.later(x * 2))
494
traversed.value // Safe computation
495
```
496
497
## Next Steps
498
499
This introduction covers the fundamental concepts and common patterns. For detailed documentation on specific areas:
500
501
- **[Core Type Classes](core-type-classes.md)** - Complete type class hierarchy and methods
502
- **[Data Types](data-types.md)** - All data types including collections and validation types
503
- **[Monad Transformers](monad-transformers.md)** - Stacking multiple effects
504
- **[Error Handling](error-handling.md)** - Error handling patterns and best practices
505
- **[Syntax Extensions](syntax-extensions.md)** - All available syntax and operators
506
- **[Instances](instances.md)** - Type class instances for standard library types
507
508
Each section provides comprehensive API documentation with practical examples for effective usage of cats-core in functional Scala programming.