Bogoware.Monads porta due degli strumenti più semplici della programmazione funzionale nel C# idiomatico: un Maybe<T> per un valore che può mancare, e un Result<T> per un’operazione che può fallire. Lo scopo non è far somigliare C# a Haskell. È spostare due intere famiglie di bug dal runtime al sistema dei tipi. Un valore che potrebbe non esserci è un Maybe<T>, e il caso vuoto non si può dimenticare. Un’operazione che potrebbe fallire restituisce un Result<T>, e il fallimento è un valore con cui devi fare i conti, non un’eccezione che srotola lo stack da un punto che non stavi guardando.

È la stessa inclinazione che sta dietro agli articoli: rendere espliciti i casi scomodi e farli controllare al compilatore. I null e le eccezioni vaganti sono complicazione accidentale, quella che il buon design tiene fuori dai piedi; un Maybe o un Result nella firma è il modello che dice la verità su quello che può succedere.

Usage.cs
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}");

Si compone come ci si aspetta: Map, Bind, Match, sintassi di query LINQ, overload asincroni e helper per collezioni IEnumerable<Maybe<T>> e IEnumerable<Result<T>>. Gli errori sono una piccola gerarchia estensibile, non stringhe, così un fallimento significa ancora qualcosa quando arriva al chiamante. Supporta .NET Standard 2.1 e .NET 8/9/10.