MonadicSharp 1.2.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package MonadicSharp --version 1.2.0
                    
NuGet\Install-Package MonadicSharp -Version 1.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MonadicSharp" Version="1.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MonadicSharp" Version="1.2.0" />
                    
Directory.Packages.props
<PackageReference Include="MonadicSharp" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add MonadicSharp --version 1.2.0
                    
#r "nuget: MonadicSharp, 1.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#addin nuget:?package=MonadicSharp&version=1.2.0
                    
Install as a Cake Addin
#tool nuget:?package=MonadicSharp&version=1.2.0
                    
Install as a Cake Tool

MonadicSharp

NuGet Version NuGet Downloads License: MIT GitHub NuGet .NET C#

๐Ÿ† Created by Danny4897 (aka Klexir on NuGet) | ๐Ÿ“ฆ Available on NuGet.org

A modern functional programming library for C# featuring Result<T>, Option<T>, Railway-Oriented Programming, and fluent pipeline composition. Build robust applications with elegant error handling and monadic patterns.

โœจ Features

  • ๐Ÿšฆ Result<T> - Railway-oriented programming for error handling
  • ๐ŸŽฏ Option<T> - Null-safe operations and optional values
  • ๐Ÿ”„ Fluent Pipelines - Chain operations with elegant syntax
  • โšก Async Support - Full async/await compatibility
  • ๐Ÿ›ก๏ธ Type Safety - Leverage C#'s type system for bulletproof code
  • ๐Ÿ“ฆ Zero Dependencies - Lightweight and self-contained

๐Ÿš€ Quick Start

Installation

dotnet add package MonadicSharp

Basic Usage

using MonadicSharp;
using MonadicSharp.Extensions;

// Result<T> for error handling
var result = Result.Success(42)
    .Map(x => x * 2)
    .Bind(x => x > 50 ? Result.Success(x) : Result.Failure("Too small"))
    .Map(x => $"Final value: {x}");

result.Match(
    onSuccess: value => Console.WriteLine(value),
    onFailure: error => Console.WriteLine($"Error: {error}")
);

// Option<T> for null-safe operations
var user = GetUser()
    .Map(u => u.Email)
    .Filter(email => email.Contains("@"))
    .GetValueOrDefault("no-email@example.com");

๐Ÿ”ง Core Types

Result<T>

Railway-oriented programming for elegant error handling:

// Success path
var success = Result.Success("Hello World");

// Failure path
var failure = Result.Failure<string>("Something went wrong");

// Chaining operations
var result = GetUser(id)
    .Bind(ValidateUser)
    .Bind(SaveUser)
    .Map(u => u.Id);

Option<T>

Null-safe operations without null reference exceptions:

// Some value
var some = Option.Some(42);

// No value
var none = Option.None<int>();

// Safe operations
var result = GetUser()
    .Map(u => u.Name)
    .Filter(name => name.Length > 0)
    .GetValueOrDefault("Anonymous");

๐Ÿ”„ Pipeline Composition

Build complex data processing pipelines:

var pipeline = Pipeline
    .Start<string>()
    .Then(ParseNumber)
    .Then(ValidateRange)
    .Then(FormatOutput);

var result = await pipeline.ExecuteAsync("42");

๐ŸŽฏ Error Handling Patterns

Traditional Approach (Problematic)

public User GetUser(int id)
{
    var user = database.Find(id);
    if (user == null) 
        throw new UserNotFoundException();
    
    if (!user.IsActive)
        throw new UserInactiveException();
        
    return user;
}

MonadicSharp Approach (Clean)

public Result<User> GetUser(int id)
{
    return database.Find(id)
        .ToResult("User not found")
        .Bind(ValidateUserActive);
}

private Result<User> ValidateUserActive(User user)
{
    return user.IsActive 
        ? Result.Success(user)
        : Result.Failure("User is inactive");
}

๐Ÿ“– API Reference

Result<T> Methods

  • Success<T>(T value) - Create a successful result
  • Failure<T>(string error) - Create a failed result
  • Map<TResult>(Func<T, TResult> func) - Transform the success value
  • Bind<TResult>(Func<T, Result<TResult>> func) - Chain operations
  • Match<TResult>(Func<T, TResult> onSuccess, Func<string, TResult> onFailure) - Pattern match
  • IsSuccess - Check if result is successful
  • IsFailure - Check if result has failed
  • Value - Get the success value (throws if failed)
  • Error - Get the error message (empty if successful)

Option<T> Methods

  • Some<T>(T value) - Create an option with value
  • None<T>() - Create an empty option
  • Map<TResult>(Func<T, TResult> func) - Transform the value if present
  • Bind<TResult>(Func<T, Option<TResult>> func) - Chain operations
  • Filter(Func<T, bool> predicate) - Filter based on condition
  • Match<TResult>(Func<T, TResult> onSome, Func<TResult> onNone) - Pattern match
  • GetValueOrDefault(T defaultValue) - Get value or default
  • HasValue - Check if option has a value
  • Value - Get the value (throws if empty)

Extension Methods

// Convert nullable to Option
string? nullable = GetNullableString();
var option = nullable.ToOption();

// Convert to Result
var result = option.ToResult("Value was null");

// Async operations
var asyncResult = await GetUserAsync(id)
    .MapAsync(user => user.Email)
    .BindAsync(ValidateEmailAsync);

๐Ÿ—๏ธ Requirements

  • .NET 8.0 or later
  • C# 10.0 or later

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿค Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

๐Ÿ“š Learn More


Made with โค๏ธ by Danny4897

FunctionalSharp

Una libreria .NET che fornisce implementazioni di tipi monadici e funzionali per C#.

Caratteristiche

  • Implementazione di Option<T> per gestire valori opzionali
  • Implementazione di Result<T> per gestire operazioni che possono fallire
  • Supporto per operazioni asincrone con Task
  • Integrazione con Entity Framework Core
  • Pipeline funzionali concise

Installazione

dotnet add package MonadicSharp

Esempi di Utilizzo

Gestione di Valori Opzionali

// Creazione di un Option
var someValue = Option<int>.Some(42);
var noneValue = Option<int>.None;

// Pattern matching
var result = someValue.Match(
    some: value => $"Il valore รจ {value}",
    none: () => "Nessun valore"
);

// Map e Bind
var doubled = someValue.Map(x => x * 2);
var maybeString = someValue.Bind(x => x > 0 ? Option<string>.Some(x.ToString()) : Option<string>.None);

Gestione di Operazioni che Possono Fallire

// Creazione di un Result
var success = Result<int>.Success(42);
var failure = Result<int>.Failure(Error.Create("Operazione fallita"));

// Pattern matching
var result = success.Match(
    success: value => $"Operazione riuscita: {value}",
    failure: error => $"Errore: {error.Message}"
);

// Map e Bind
var doubled = success.Map(x => x * 2);
var maybeString = success.Bind(x => x > 0 ? Result<string>.Success(x.ToString()) : Result<string>.Failure(Error.Create("Valore non valido")));

Pipeline Funzionali Con Entity Framework

// Creazione di un utente con validazione
public async Task<Result<User>> CreateUserAsync(UserDto userDto)
{
    return await Result<UserDto>.Success(userDto)
        .Map(ValidateUserDto)
        .Bind(MapToUser)
        .Bind(user => _userRepository.Users.AddAsync(user))
        .BindAsync(SaveChangesAsync)
        .Success(user => Result<User>.Success(user))
        .Failure(error => Result<User>.Failure(error));
}

// Recupero di un utente con gestione errori
public async Task<Result<User>> GetUserByIdAsync(int id)
{
    return await Result<int>.Success(id)
        .Bind(id => _userRepository.Users.FindAsync(id))
        .BindAsync(user => user.ToResult("Utente non trovato"))
        .Success(user => Result<User>.Success(user))
        .Failure(error => Result<User>.Failure(error));
}

// Aggiornamento di un utente con validazione
public async Task<Result<User>> UpdateUserAsync(int id, UserDto userDto)
{
    return await Result<(int id, UserDto dto)>.Success((id, userDto))
        .Map(tuple => (tuple.id, ValidateUserDto(tuple.dto)))
        .Bind(tuple => _userRepository.Users.FindAsync(tuple.id)
            .BindAsync(user => user.ToResult("Utente non trovato"))
            .Bind(user => MapToUser(tuple.dto).Map(dto => (user, dto))))
        .Bind(tuple => _userRepository.Users.Update(tuple.user))
        .BindAsync(SaveChangesAsync)
        .Success(user => Result<User>.Success(user))
        .Failure(error => Result<User>.Failure(error));
}

Operazioni Asincrone

// Combinazione di operazioni asincrone
public async Task<Result<User>> GetUserWithDetailsAsync(int userId)
{
    return await Result<int>.Success(userId)
        .BindAsync(async id => 
        {
            var user = await _userRepository.Users.FindAsync(id);
            var roles = await _userRepository.Roles.WhereAsync(r => r.UserId == id);
            return (user, roles);
        })
        .BindAsync(async tuple => 
        {
            var user = await tuple.user.ToResult("Utente non trovato");
            var roles = await tuple.roles;
            return Result<User>.Success(user with { Roles = roles });
        });
}

Contribuire

Le contribuzioni sono benvenute! Per favore, apri una issue per discutere i cambiamenti che vorresti fare.

Licenza

Questo progetto รจ licenziato sotto la licenza MIT - vedi il file LICENSE per i dettagli.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.3.3 128 6/26/2025
1.3.0 281 6/12/2025
1.2.0 279 6/10/2025
1.1.0 247 6/9/2025
1.0.0 110 6/7/2025

v1.2.0: Changed namespace from FunctionalSharp to MonadicSharp to match NuGet package name
v1.1.0: Added Either<TLeft, TRight> type for representing two alternative types