Async Programming with Monads
Both Result<T> and Maybe<T> provide full async support for all major operations.
Async Result Operations
Async Map
var result = await Result.Success("file.txt")
.Map(async fileName => await File.ReadAllTextAsync(fileName));
Async Bind
public async Task<Result<User>> GetUserAsync(int id) =>
await ValidateId(id)
.Bind(async validId => await database.GetUserAsync(validId));
Async Side Effects
var result = await CreateUserAsync(email)
.IfSuccess(async user => await SendWelcomeEmailAsync(user))
.IfFailure(async error => await LogErrorAsync(error));
Async Match
var message = await result.Match(
async user => await FormatUserDetailsAsync(user),
async error => await FormatErrorMessageAsync(error)
);
Async Ensure
var validated = await result
.Ensure(async user => await IsUserActiveAsync(user),
new LogicError("User is not active"));
Async Maybe Operations
Async Map
var maybe = await Maybe.Some("data")
.Map(async data => await ProcessDataAsync(data));
Async Bind
var result = await Maybe.Some(userId)
.Bind(async id => await FindUserAsync(id));
Async Side Effects
await maybe
.IfSome(async value => await ProcessValueAsync(value))
.IfNone(async () => await HandleMissingValueAsync());
Task Extensions
All methods work seamlessly with Task<Result<T>> and Task<Maybe<T>>:
public async Task<Result<ProcessedData>> ProcessUserDataAsync(int userId)
{
return await GetUserAsync(userId) // Task<Result<User>>
.Bind(async user => await GetUserDataAsync(user.Id))
.Map(async data => await ProcessDataAsync(data))
.IfSuccess(async result => await CacheResultAsync(result));
}
Safe Async Execution
// Catches exceptions as RuntimeError
var result = await Result.Execute(async () =>
await RiskyAsyncOperation()
);