Bogoware.Monads brings two of functional programming’s most useful tools to idiomatic C#: a Maybe<T> for values that may be absent, and a Result<T> for operations that may fail. The point is not to make C# look like Haskell — it is to move two whole classes of bug out of runtime and into the type system. A value that might not exist is a Maybe<T>, so you cannot forget to handle the empty case. An operation that might fail returns a Result<T>, so the failure is a value you have to deal with rather than an exception that unwinds the stack when you least expect it.
That bias — make the awkward cases explicit, push them to compile time — is the same one behind the domain-modelling work in the articles. Nulls and stray exceptions are exactly the kind of accidental complication good design tries to keep out of the way; a Maybe or a Result in the signature is the model telling the truth about what can happen.
using Bogoware.Monads;
// Absence lives in the type — no nulls, no NullReferenceExceptions.
public string DisplayName(Maybe<string> nickname, string fallback) =>
nickname.Map(n => $"@{n}").GetValue(fallback);
// Failure is a value you must handle — no hidden exceptions.
public Result<User> Register(string email, string password) =>
ValidateEmail(email)
.Bind(() => ValidatePassword(password))
.Map(() => new User(email, password));
string message = Register(email, password).Match(
user => $"Welcome, {user.Email}",
error => $"Could not register: {error.Message}"); The library composes cleanly — Map, Bind, Match, LINQ query syntax, async overloads, and collection helpers for IEnumerable<Maybe<T>> and IEnumerable<Result<T>> — and ships a small, extensible error hierarchy so failures stay meaningful rather than collapsing into strings. It targets .NET Standard 2.1 and .NET 8/9/10.
- Package — nuget.org/packages/Bogoware.Monads
- Source — github.com/bogoware/monads
- Docs — bogoware.github.io/Monads