Introduction to Sealed Monad
Sealed Monad is a Scala library that provides elegant, business logic-oriented, for-comprehension-style error handling. It enhances code readability and maintainability by allowing you to express business logic with clear error handling in a linear, declarative way.
What is Sealed Monad?
Sealed Monad can be thought of as "EitherT on steroids, with more human-readable method names." It provides a clean, intuitive, and type-safe way to handle errors in functional programming, particularly in complex business logic scenarios.
If you've ever found yourself writing deeply nested pattern matching or complex conditional structures for error handling, Sealed Monad offers a more elegant approach.
Key Benefits
- Linear Code Flow: Write top-down, sequential code that's easy to follow
- Type Safety: Enforce handling of all error cases at compile time
- Reduced Boilerplate: No need to map between different error types when combining functions
- For-Comprehension Friendly: Leverage Scala's for-comprehensions for clean, pipeline-style code
- Business-Logic Oriented: Error handling focused on representing business outcomes, not just technical errors
Quick Example
Here's a simple example showing how Sealed Monad can clean up a typical validation workflow:
import pl.iterators.sealedmonad.syntax._
import cats.effect.IO
// Define our result ADT
sealed trait CreateUserResponse
object CreateUserResponse {
case class Success(id: String) extends CreateUserResponse
case object EmailAlreadyExists extends CreateUserResponse
case object InvalidEmail extends CreateUserResponse
case object PasswordTooWeak extends CreateUserResponse
}
def createUser(request: CreateUserRequest): IO[CreateUserResponse] = {
(for {
// Validate email format
_ <- validateEmail(request.email)
.ensure(isValid => isValid, CreateUserResponse.InvalidEmail)
// Check if email already exists
emailExists <- userRepository.emailExists(request.email).seal
_ <- (!emailExists).pure[IO]
.ensure(notExists => notExists, CreateUserResponse.EmailAlreadyExists)
// Validate password strength
_ <- validatePassword(request.password)
.ensure(isStrong => isStrong, CreateUserResponse.PasswordTooWeak)
// All validations passed, create the user
userId <- userRepository.create(request.email, request.password).seal
} yield CreateUserResponse.Success(userId)).run
}
Installation
Add the following to your build.sbt
:
libraryDependencies += "pl.iterators" %% "sealed-monad" % "1.3"
For more detailed installation instructions and examples, see the Installation Guide.
Documentation
- Motivations & Core Concepts
- Practical Use Cases
- API Reference
- Best Practices
- Comparison with Other Approaches
- Migration Guide
- FAQ
License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.