jflepp-maybe
/jflepp-maybe
Obsługuje wartości opcjonalne w C# biblioteką JFlepp.Maybe (Maybe i Option): eliminacja null, łańcuchowanie monadyczne i składnia zapytań LINQ.
- Autor
- Tyler-R-Kendrick ↗
- Repozytorium
- agent-skills ↗
- Licencja
- MIT
- Ostatnia zmiana repozytorium
- 09.06.2026
Ocena i bezpieczeństwo
- Pliki w paczce
- 21
- Skrypty
- 0
- Komentarze HTML
- 0
- Adresy URL w SKILL.md
- 2
Brak sygnałów. Repozytorium zmienione 09.06.2026, bez odwołań do wycofanych modeli i API.
MIT, otwarta: można używać i zmieniać, z zachowaniem informacji o autorze.
Co robi i kiedy
Obsługuje wartości opcjonalne w C# biblioteką JFlepp.Maybe (Maybe i Option): eliminacja null, łańcuchowanie monadyczne i składnia zapytań LINQ.
Oryginalny opis (EN)
Use when handling optional values with JFlepp.Maybe, a lightweight Maybe/Option monad library for C#. USE FOR: optional value handling with Maybe<T>, null elimination, monadic chaining of optional values, LINQ query syntax over optional values DO NOT USE FOR: full functional programming library (use language-ext), complex error handling with error types (use Result/Either), parser combinators (use pidgin)
Jak działa
- Overview
- NuGet Package
- Basic Usage
- Map and Bind
- LINQ Query Syntax
- Where (Filter)
- Converting from Nullable Types
- Practical Repository Example
- API Endpoint Integration
- Maybe vs Alternatives
Podgląd SKILL.md
---
name: jflepp-maybe
description: |
Use when handling optional values with JFlepp.Maybe, a lightweight Maybe/Option monad library for C#.
USE FOR: optional value handling with Maybe<T>, null elimination, monadic chaining of optional values, LINQ query syntax over optional values
DO NOT USE FOR: full functional programming library (use language-ext), complex error handling with error types (use Result/Either), parser combinators (use pidgin)
license: MIT
metadata:
displayName: "JFlepp.Maybe"
author: "Tyler-R-Kendrick"
version: "1.0.0"
compatibility: claude, copilot, cursor
references:
- title: "JFlepp.Maybe GitHub Repository"
url: "https://github.com/fl3pp/JFlepp.Maybe"
- title: "JFlepp.Maybe NuGet Package"
url: "https://www.nuget.org/packages/JFlepp.Maybe"
---
# JFlepp.Maybe
## Overview
JFlepp.Maybe is a lightweight .NET library providing a `Maybe<T>` type for representing optional values without using null. It implements the Maybe monad with `Select` (map), `SelectMany` (bind), and `Where` (filter) operations, enabling LINQ query syntax over optional values. The library is intentionally minimal, focusing on correct optional value semantics with a small API surface.
## NuGet Package
- `JFlepp.Maybe` -- core Maybe<T> type
## Basic Usage
```csharp
using JFlepp.Maybe;
// Creating Maybe values
Maybe<int> someValue = Maybe.Some(42);
Maybe<int> noValue = Maybe.None<int>();
// Check for value
if (someValue.HasValue)
{
Console.WriteLine($"Value: {someValue.Value}");
}
// Match to handle both cases
string result = someValue.Match(
some: value => $"Found: {value}",
none: () => "Not found");
// OrElse for default values
int withDefault = noValue.OrElse(0); // 0
int withLazy = noValue.OrElse(() => ComputeExpensiveDefault()); // lazy evaluation
```
## Map and Bind
```csharp
using JFlepp.Maybe;
// Map: transform the inner value if present
Maybe<string> maybeName = Maybe.Some("Alice");
Maybe<int> nameLength = maybeName.Select(name => name.Length);
// nameLength = Some(5)
Maybe<string> noName = Maybe.None<string>();
Maybe<int> noLength = noName.Select(name => name.Length);
// noLength = None
// Bind (SelectMany): chain operations that return Maybe
Maybe<User> FindUser(int id) =>
users.ContainsKey(id)
? Maybe.Some(users[id])
: Maybe.None<User>();
Maybe<Address> GetAddress(User user) =>
user.Address is not null
? Maybe.Some(user.Address)
: Maybe.None<Address>();
Maybe<string> GetCity(Address address) =>
!string.IsNullOrEmpty(address.City)
? Maybe.Some(address.City)
: Maybe.None<string>();
// Chain with SelectMany
Maybe<string> userCity = FindUser(123)
.SelectMany(user => GetAddress(user))
.SelectMany(address => GetCity(address));
```
## LINQ Query Syntax
```csharp
using JFlepp.Maybe;
// LINQ query syntax for readable chaining
Maybe<string> cityName =
from user in FindUser(123)
from address in GetAddress(user)
from city in GetCity(address)
select city.ToUpperInvariant();
// With intermediate transformations
Maybe<OrderSummary> summary =
from customer in FindCustomer(customerId)
from order in GetLatestOrder(customer.Id)
from total in CalculateTotal(order)
where total > 0
select new OrderSummary(customer.Name, order.Id, total);
```
## Where (Filter)
```csharp
using JFlepp.Maybe;
// Filter: keep value only if predicate is true
Maybe<int> positive = Maybe.Some(42).Where(x => x > 0); // Some(42)
Maybe<int> filtered = Maybe.Some(-5).Where(x => x > 0); // None
// Combining filter with map
Maybe<string> validEmail = Maybe.Some("user@example.com")
.Where(e => e.Contains('@'))
.Select(e => e.ToLowerInvariant());
```
## Converting from Nullable Types
```csharp
using JFlepp.Maybe;
// Extension methods for nullable conversion
public static class MaybeExtensions
{
public static Maybe<T> ToMaybe<T>(this T? value) where T : class
=> value is not null ? Maybe.Some(value) : Maybe.None<T>();
public static Maybe<T> ToMaybe<T>(this T? value) where T : struct
=> value.HasValue ? Maybe.Some(value.Value) : Maybe.None<T>();
}
// Usage with nullable returns
string? nullableName = GetNameOrNull();
Maybe<string> maybeName = nullableName.ToMaybe();
int? nullableAge = GetAgeOrNull();
Maybe<int> maybeAge = nullableAge.ToMaybe();
// Converting Dictionary lookups
public static Maybe<TValue> TryGetMaybe<TKey, TValue>(
this IDictionary<TKey, TValue> dictionary, TKey key)
=> dictionary.TryGetValue(key, out var value)
? Maybe.Some(value)
: Maybe.None<TValue>();
Maybe<Customer> customer = customerDictionary.TryGetMaybe("cust-123");
```
## Practical Repository Example
```csharp
using JFlepp.Maybe;
public interface ICustomerRepository
{
Maybe<Customer> FindById(Guid id);
Maybe<Customer> FindByEmail(string email);
}
public class CustomerRepository : ICustomerRepository
{
private readonly AppDbContext _db;
public CustomerRepository(AppDbContext db) => _db = db;
public Maybe<Customer> FindById(Guid id)
{
var customer = _db.Customers.Find(id);
return customer is not null
? Maybe.Some(customer)
: Maybe.None<Customer>();
}
public Maybe<Customer> FindByEmail(string email)
{
var customer = _db.Customers.FirstOrDefault(c => c.Email == email);
return customer is not null
? Maybe.Some(customer)
: Maybe.None<Customer>();
}
}
// Usage in a service
public class CustomerService
{
private readonly ICustomerRepository _repository;
public CustomerService(ICustomerRepository repository)
=> _repository = repository;
public string GetCustomerGreeting(Guid id) =>
_repository.FindById(id)
.Select(c => $"Hello, {c.Name}!")
.OrElse("Customer not found");
public Maybe<decimal> GetCustomerBalance(Guid id) =>
_repository.FindById(id)
.Select(c => c.Balance)
.Where(balance => balance >= 0);
}
```
## API Endpoint Integration
```csharp
app.MapGet("/customers/{id:guid}", (Guid id, ICustomerRepository repo) =>
{
return repo.FindById(id)
.Match<IResult>(
some: customer => Results.Ok(customer),
none: () => Results.NotFound());
});
app.MapGet("/customers/{id:guid}/address/city", (Guid id, ICustomerRepository repo) =>
{
var city =
from customer in repo.FindById(id)
from address in GetAddress(customer)
from cityName in GetCity(address)
select cityName;
return city.Match<IResult>(
some: c => Results.Ok(new { city = c }),
none: () => Results.NotFound());
});
```
## Maybe vs Alternatives
| Feature | JFlepp.Maybe | language-ext Option | C# Nullable |
|---------|-------------|-------------------|-------------|
| Type | `Maybe<T>` | `Option<T>` | `T?` |
| LINQ support | Yes | Yes | No |
| Value type | Class-based | Struct-based | Compiler feature |
| API surface | Minimal | Extensive | N/A |
| Library size | Tiny | Large (full FP) | Built-in |
| Match method | Yes | Yes | No (manual null check) |
| Best for | Lightweight optional | Full FP ecosystem | Simple null safety |
## Best Practices
- Use `Maybe.Some(value)` for present values and `Maybe.None<T>()` for absent values; never pass null where a `Maybe<T>` is expected.
- Use `Select` (map) to transform the inner value and `SelectMany` (bind) to chain operations that themselves return `Maybe<T>`.
- Prefer LINQ query syntax (`from ... in ... select`) when chaining more than two `SelectMany` operations for improved readability.
- Use `OrElse` with a default value at the boundary of your application (e.g., in API endpoints or UI code) to convert from `Maybe<T>` to a concrete value.
- Use `Where` to filter optional values based on a predicate, converting `Some` to `None` when the condition is not met.
- Write extension methods to convert between nullable types (`T?`) and `Maybe<T>` for interop with existing APIs that return null.
- Return `Maybe<T>` from repository and service methods instead of nullable types to make the possibility of absence explicit in the type signature.
- Use `Match` with both `some` and `none` handlers to ensure both cases are handled explicitly, preventing accidental null-like access patterns.
- Avoid calling `.Value` directly without checking `.HasValue` first; prefer `Match`, `Select`, or `OrElse` for safe access.
- Keep the `JFlepp.Maybe` library for simple optional value scenarios; if you need `Either`, `Try`, or full monadic composition, consider language-ext instead.
Pliki w paczce (21)
- AGENTS.md 8 KB
- README.md 1 KB
- SKILL.md 8 KB
- metadata.json 1 KB
- rules/_sections.md 2 KB
- rules/_template.md 1 KB
- rules/jflepp-maybe-avoid-calling.md 1 KB
- rules/jflepp-maybe-avoid-mixing-with-null.md 1 KB
- rules/jflepp-maybe-chain-operations-with-select-selectmany.md 1 KB
- rules/jflepp-maybe-keep-the-jflepp.md 1 KB
- rules/jflepp-maybe-prefer-linq-query-syntax-from.md 1 KB
- rules/jflepp-maybe-return-maybe-t-from-repository-and-service-methods.md 1 KB
- rules/jflepp-maybe-use-match-with-both-some-and-none-handlers-to-ensure.md 1 KB
- rules/jflepp-maybe-use-maybe-just-for-present-values.md 1 KB
- rules/jflepp-maybe-use-maybe-nothing-for-absent-values.md 1 KB
- rules/jflepp-maybe-use-maybe.md 1 KB
- rules/jflepp-maybe-use-orelse-for-default-values.md 1 KB
- rules/jflepp-maybe-use-orelse-with-a-default-value-at-the-boundary-of-your.md 1 KB
- rules/jflepp-maybe-use-select-map-to-transform-the-inner-value-and.md 1 KB
- rules/jflepp-maybe-use-where-to-filter-optional-values-based-on-a-predicate.md 1 KB
- rules/jflepp-maybe-write-extension-methods-to-convert-between-nullable-types.md 1 KB
Wersje
W bazie nie ma innych skilli o nazwie jflepp-maybe.
Migawka bazy z 28.10.2026 · wersja paczki 9b17fdbd8350 (skrót SHA-256 całej paczki)
Zgłoś problem z tym skillem: szkodliwa treść, błędny opis albo prośba autora o usunięcie.
Podobne skille
- 100optional
Wdraża wzorzec Optional i Maybe w C#, aby wyeliminować wyjątki null reference i jawnie wyrazić brak wartości w systemie typów, w tym łańcuchowanie monadyczne i projekt API z jawną opcjonalnością. - 100language-ext
Stosuje wzorce programowania funkcyjnego w C# z biblioteką language-ext: Option, Either, Try, niemutowalne kolekcje, kompozycja monadyczna w LINQ oraz Eff i Aff. - 100golang-samber-mo
Obsługuje typy monadyczne Go z samber/mo (Option, Result, Either, Future, IO, Task, State) do bezpiecznych wartości opcjonalnych, obsługi błędów i kompozycji funkcyjnej. - 100fp-option-ref
Podaje skrócone odniesienie do typu Option w fp-ts, przy obsłudze wartości nullable i opcjonalnych danych oraz unikaniu sprawdzania null. - 100fp-option-ref
Podaje skrócone odniesienie do typu Option w fp-ts, przy obsłudze wartości nullable i opcjonalnych danych oraz unikaniu sprawdzania null. - 95csharp-linq
Opisuje LINQ w C#: składnię zapytań i metod, odroczone wykonanie, drzewa wyrażeń i optymalizację wydajności.