Przejdź do treści
Biblioteka skilli
Programowanie · Budowanie i kod

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.

Repozytorium
agent-skills ↗
Licencja
MIT
Ostatnia zmiana repozytorium
09.06.2026

Ocena i bezpieczeństwo

100/ 100Klasa: dobry
Format25 / 25
Frontmatter z nazwą i opisem, poprawna nazwa, opis do 1024 znaków, nazwa zgodna z folderem.
Odkrywalność25 / 25
Opis mówi, kiedy użyć skilla, ma sensowną długość i jest w 3. osobie.
Treść35 / 35
Co najmniej 150 słów i do 500 linii, nagłówki, listy kroków, przykłady albo kod.
Higiena15 / 15
Bez zaślepek typu TODO, bez ścieżek Windows, z licencją.
Ryzykobrak sygnałów w skanie
Pliki w paczce
21
Skrypty
0
Komentarze HTML
0
Adresy URL w SKILL.md
2
Przestarzałość

Brak sygnałów. Repozytorium zmienione 09.06.2026, bez odwołań do wycofanych modeli i API.

Licencja

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

  1. Overview
  2. NuGet Package
  3. Basic Usage
  4. Map and Bind
  5. LINQ Query Syntax
  6. Where (Filter)
  7. Converting from Nullable Types
  8. Practical Repository Example
  9. API Endpoint Integration
  10. Maybe vs Alternatives
Sekcje z nagłówków SKILL.md, w oryginale · 234 linii, 949 słów
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.

Uwagi i zgłoszenia

Wiadomość trafi do Bartosza Sokolińskiego. Adres e-mail jest potrzebny tylko do odpowiedzi. Szczegóły w polityce prywatności.