Skip to main content

Result<T> Monad

The Result<T> monad is designed for modeling operations that can either fail or return a value. It is a generic type, with T representing the type of the value returned by the successful operation.

Design Goals

Result<T> provides a set of methods that facilitate chaining operations in a functional way:

MethodPurpose
MapTransform the value (happy flow)
MapErrorTransform the error (unhappy flow)
BindChain operations returning Result<T>
MatchHandle both success and failure paths
RecoverWithRecover from an error
EnsureAssert a condition on the value
IfSuccessExecute side effects on success
IfFailureExecute side effects on failure

Creating Results

// Success
var success = Result.Success(42);
var unitSuccess = Result.Unit; // For void operations

// Failure
var failure = Result.Failure<int>("Something went wrong");
var customFailure = Result.Failure<int>(new CustomError("Details"));

// From values
var fromValue = Result.From(42);

Core Operations

Map

Transforms the value if the result is successful:

var result = Result.Success(42);
var doubled = result.Map(x => x * 2); // Result<int> with 84
var text = result.Map(x => $"Value: {x}"); // Result<string>

Bind

Chains operations that return Result<T>:

public Result<int> ParseNumber(string text) =>
int.TryParse(text, out var num)
? Result.Success(num)
: Result.Failure<int>("Invalid number");

var result = ParseNumber("42")
.Bind(n => ValidateRange(n))
.Map(n => n * 2);

Match

Handles both success and failure cases:

var message = result.Match(
value => $"Success: {value}",
error => $"Failed: {error.Message}"
);

Unsafe Methods

Use sparingly - these deviate from functional paradigm:

// Extract value (throws if failure)
var value = result.Value;
var value2 = result.GetValueOrThrow();

// Extract error (throws if success)
var error = failedResult.Error;

// Throw if failure
result.ThrowIfFailure();

See Also