Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.direnv/
*.code-workspace
/target
.vscode
.vscode
.claude/test-cache/
36 changes: 36 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,42 @@ eval "$(direnv export bash 2>/dev/null)"; cargo doc --workspace --all-features -
eval "$(direnv export bash 2>/dev/null)"; cargo test --workspace --all-features
```

### Test Output Caching

To avoid re-running expensive test suites when source files haven't changed, cache test outputs:

**Cache file location:** `.claude/test-cache/` (gitignored)

**After running tests**, save the output:
```bash
mkdir -p .claude/test-cache
eval "$(direnv export bash 2>/dev/null)"; cargo test --workspace --all-features 2>&1 | tee .claude/test-cache/test-output.txt
# Record the timestamp of the newest source file at cache time
find fp-library/src fp-macros/src -name '*.rs' -printf '%T@\n' | sort -rn | head -1 > .claude/test-cache/source-timestamp.txt
```

**Before re-running tests**, check if cache is still valid:
```bash
# Get newest source file timestamp
LATEST=$(find fp-library/src fp-macros/src -name '*.rs' -printf '%T@\n' | sort -rn | head -1)
CACHED=$(cat .claude/test-cache/source-timestamp.txt 2>/dev/null || echo "0")
if [ "$LATEST" = "$CACHED" ]; then
echo "=== CACHED TEST OUTPUT (no source changes) ==="
cat .claude/test-cache/test-output.txt
else
echo "=== Source files changed, re-running tests ==="
eval "$(direnv export bash 2>/dev/null)"; cargo test --workspace --all-features 2>&1 | tee .claude/test-cache/test-output.txt
echo "$LATEST" > .claude/test-cache/source-timestamp.txt
fi
```

**Always invalidate** (re-run tests) when:
- Any `.rs` file under `fp-library/src/` or `fp-macros/src/` has been modified since the cached timestamp
- `Cargo.toml` files have changed
- Test files under `tests/` have changed

**Use cached output** when you just need to re-check results (e.g., confirming a test name, reviewing output) and no source files have changed.

## Language Server & Code Intelligence

This repository has rust-analyzer configured via MCP (Model Context Protocol). Claude Code can use the LSP tool to access:
Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ A functional programming library for Rust featuring your favourite higher-kinded

- **Higher-Kinded Types (HKT):** Implemented using lightweight higher-kinded polymorphism (type-level defunctionalization/brands).
- **Macros:** Procedural macros for working with HKTs and monadic code:
- **HKT:** `trait_kind!`, `impl_kind!`, `Apply!` for defining and applying higher-kinded type encodings
- **HKT:** `trait_kind!`, `impl_kind!`, `Apply!`, `#[kind]` for defining and applying higher-kinded type encodings
- **Do-Notation:** `m_do!` for monadic do-notation, `a_do!` for applicative do-notation
- **Type Classes:** A comprehensive collection of standard type classes including:
- **Core:** `Functor`, `Contravariant`, `Pointed`, `Applicative`, `Semiapplicative`, `Monad`, `Semimonad`, `Semigroup`, `Monoid`, `Foldable`, `Traversable`, `Alt`, `Plus`, `Alternative`
Expand Down
59 changes: 46 additions & 13 deletions docs/release-process.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,28 +82,61 @@ git checkout -b release/fp-library-vX.Y.Z
Run the full suite of checks locally to catch issues before the PR:

```bash
# Check compilation
cargo check

# Run all tests (unit, integration, and doc)
cargo test
# Format code
cargo fmt --all

# Run linter
cargo clippy
cargo clippy --workspace --all-features

# Verify documentation builds (must produce zero warnings)
cargo doc --workspace --all-features --no-deps

# Run all tests
cargo test --workspace --all-features
```

#### Test Output Caching

To avoid re-running expensive test suites when source files haven't changed, cache test outputs:

**Cache file location:** `.claude/test-cache/` (gitignored)

# Verify documentation builds and looks correct
cargo doc --open
**After running tests**, save the output:
```bash
mkdir -p .claude/test-cache
cargo test --workspace --all-features 2>&1 | tee .claude/test-cache/test-output.txt
# Record the timestamp of the newest source file at cache time
find fp-library/src fp-macros/src -name '*.rs' -printf '%T@\n' | sort -rn | head -1 > .claude/test-cache/source-timestamp.txt
```

**Before re-running tests**, check if cache is still valid:
```bash
# Get newest source file timestamp
LATEST=$(find fp-library/src fp-macros/src -name '*.rs' -printf '%T@\n' | sort -rn | head -1)
CACHED=$(cat .claude/test-cache/source-timestamp.txt 2>/dev/null || echo "0")
if [ "$LATEST" = "$CACHED" ]; then
echo "=== CACHED TEST OUTPUT (no source changes) ==="
cat .claude/test-cache/test-output.txt
else
echo "=== Source files changed, re-running tests ==="
cargo test --workspace --all-features 2>&1 | tee .claude/test-cache/test-output.txt
echo "$LATEST" > .claude/test-cache/source-timestamp.txt
fi
```

**Always invalidate** (re-run tests) when:
- Any `.rs` file under `fp-library/src/` or `fp-macros/src/` has been modified since the cached timestamp
- `Cargo.toml` files have changed
- Test files under `tests/` have changed

**Use cached output** when you just need to re-check results (e.g., confirming a test name, reviewing output) and no source files have changed.

### 7. Commit and Open PR

1. Stage and commit the release changes:
1. Stage and commit the release changes (includes `Cargo.lock`, READMEs, and any other release-related updates):

```bash
git add fp-library/Cargo.toml fp-library/CHANGELOG.md
# Add fp-macros files if changed
git add fp-macros/Cargo.toml fp-macros/CHANGELOG.md

git add .
git commit -m "chore: release fp-library vX.Y.Z / fp-macros vA.B.C"
```

Expand Down
7 changes: 7 additions & 0 deletions fp-library/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.13.1] - 2026-03-14

### Changed
- **`#[kind]` attribute migration**: All 15 type class traits migrated from raw `Kind_*` supertraits to `#[kind(type Of<'a, A: 'a>: 'a;)]` attribute annotations. The generated supertrait bounds are identical; this is a source-level readability improvement only.
- **Rustdoc link improvements**: Doc comments updated to use `Kind!(...)` rustdoc links instead of raw `Kind_*` trait names for better documentation readability.
- **Native field documentation**: Replaced all `#[document_fields]` usages with native `///` doc comments directly on struct fields and enum variants across 12 types (`CatListIterator`, `Endofunction`, `Endomorphism`, `Identity`, `Lazy`, `Pair`, `Thunk`, `Trampoline`, `TryLazy`, `TryThunk`, `TryTrampoline`, `FreeInner`).

## [0.13.0] - 2026-03-13

### Added
Expand Down
4 changes: 2 additions & 2 deletions fp-library/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "fp-library"
version = "0.13.0"
version = "0.13.1"
edition = "2024"
description = "A functional programming library for Rust featuring your favourite higher-kinded types and type classes."
readme = "../README.md"
Expand All @@ -18,7 +18,7 @@ harness = false
name = "benchmarks"

[dependencies]
fp-macros = { path = "../fp-macros", version = "0.5" }
fp-macros = { path = "../fp-macros", version = "0.6" }
rayon = { version = "1.11", optional = true }
serde = { version = "1.0", optional = true, features = ["derive"] }
thiserror = "2.0"
Expand Down
3 changes: 2 additions & 1 deletion fp-library/src/classes/bifoldable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ mod inner {
/// ),
/// );
/// ```
pub trait Bifoldable: Kind_266801a817966495 {
#[kind(type Of<'a, A: 'a, B: 'a>: 'a;)]
pub trait Bifoldable {
/// Folds the bifoldable structure from right to left using two step functions.
///
/// This method performs a right-associative fold, dispatching to `f` for
Expand Down
5 changes: 3 additions & 2 deletions fp-library/src/classes/bifunctor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ mod inner {
///
/// ### Hierarchy Unification
///
/// This trait inherits from [`Kind_266801a817966495`], ensuring that all bifunctor
/// This trait inherits from [`Kind!(type Of<'a, A: 'a, B: 'a>: 'a;)`](crate::kinds::Kind_266801a817966495), ensuring that all bifunctor
/// contexts satisfy the strict lifetime requirements where both type arguments must
/// outlive the context's application lifetime.
///
Expand Down Expand Up @@ -77,7 +77,8 @@ mod inner {
/// bimap::<ResultBrand, _, _, _, _>(f, h, bimap::<ResultBrand, _, _, _, _>(g, i, err)),
/// );
/// ```
pub trait Bifunctor: Kind_266801a817966495 {
#[kind(type Of<'a, A: 'a, B: 'a>: 'a;)]
pub trait Bifunctor {
/// Maps functions over the values in the bifunctor context.
///
/// This method applies two functions to the values inside the bifunctor context, producing a new bifunctor context with the transformed values.
Expand Down
2 changes: 1 addition & 1 deletion fp-library/src/classes/category.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ mod inner {
///
/// ### Hierarchy Unification
///
/// By inheriting from [`Semigroupoid`], this trait implicitly requires [`Kind_266801a817966495`].
/// By inheriting from [`Semigroupoid`], this trait implicitly requires [`Kind!(type Of<'a, A: 'a, B: 'a>: 'a;)`](crate::kinds::Kind_266801a817966495).
/// This unification ensures that categorical identity morphisms also satisfy the strict lifetime
/// requirements where the object type must outlive the morphism's application lifetime.
///
Expand Down
3 changes: 2 additions & 1 deletion fp-library/src/classes/compactable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ mod inner {
/// plus_empty::<VecBrand, i32>(),
/// );
/// ```
pub trait Compactable: Kind_cdc7cd43dac7585f {
#[kind(type Of<'a, A: 'a>: 'a;)]
pub trait Compactable {
/// Compacts a data structure of [`Option`]s, discarding [`None`] values and keeping [`Some`] values.
#[document_signature]
///
Expand Down
5 changes: 3 additions & 2 deletions fp-library/src/classes/contravariant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ mod inner {
///
/// ### Hierarchy Unification
///
/// This trait inherits from [`Kind_cdc7cd43dac7585f`], ensuring that all contravariant
/// This trait inherits from [`Kind!(type Of<'a, A: 'a>: 'a;)`](crate::kinds::Kind_cdc7cd43dac7585f), ensuring that all contravariant
/// contexts satisfy the strict lifetime requirements where the type argument must
/// outlive the context's application lifetime.
///
Expand Down Expand Up @@ -72,7 +72,8 @@ mod inner {
/// assert_eq!(left(5), right(5));
/// assert_eq!(left(-10), right(-10));
/// ```
pub trait Contravariant: Kind_cdc7cd43dac7585f {
#[kind(type Of<'a, A: 'a>: 'a;)]
pub trait Contravariant {
/// Maps a function contravariantly over the context.
///
/// This method applies a function to the input before it is consumed by the context.
Expand Down
2 changes: 0 additions & 2 deletions fp-library/src/classes/filterable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,6 @@ mod inner {
/// Maps a function over a data structure and filters out [`None`] results.
///
/// The default implementation uses [`map`](crate::functions::map) and [`compact`](crate::functions::compact).
///
/// ### Type Signature
#[document_signature]
///
#[document_type_parameters(
Expand Down
3 changes: 2 additions & 1 deletion fp-library/src/classes/foldable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ mod inner {
/// ),
/// );
/// ```
pub trait Foldable: Kind_cdc7cd43dac7585f {
#[kind(type Of<'a, A: 'a>: 'a;)]
pub trait Foldable {
/// Folds the structure by applying a function from right to left.
///
/// This method performs a right-associative fold of the structure.
Expand Down
5 changes: 3 additions & 2 deletions fp-library/src/classes/functor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ mod inner {
///
/// ### Hierarchy Unification
///
/// This trait now inherits from [`Kind_cdc7cd43dac7585f`], ensuring that all functor
/// This trait inherits from [`Kind!(type Of<'a, A: 'a>: 'a;)`](crate::kinds::Kind_cdc7cd43dac7585f), ensuring that all functor
/// contexts satisfy the strict lifetime requirements where the type argument must
/// outlive the context's application lifetime.
///
Expand Down Expand Up @@ -84,7 +84,8 @@ mod inner {
/// map::<VecBrand, _, _>(f, map::<VecBrand, _, _>(g, vec![1, 2, 3])),
/// );
/// ```
pub trait Functor: Kind_cdc7cd43dac7585f {
#[kind(type Of<'a, A: 'a>: 'a;)]
pub trait Functor {
/// Maps a function over the values in the functor context.
///
/// This method applies a function to the value(s) inside the functor context, producing a new functor context with the transformed value(s).
Expand Down
3 changes: 2 additions & 1 deletion fp-library/src/classes/lift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ mod inner {
};

/// A type class for lifting binary functions into a context.
pub trait Lift: Kind_cdc7cd43dac7585f {
#[kind(type Of<'a, A: 'a>: 'a;)]
pub trait Lift {
/// Lifts a binary function into the context.
///
/// This method lifts a binary function to operate on values within the context.
Expand Down
3 changes: 2 additions & 1 deletion fp-library/src/classes/par_compactable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ mod inner {
/// assert_eq!(errs, vec!["e"]);
/// assert_eq!(oks, vec![1, 3]);
/// ```
pub trait ParCompactable: Kind_cdc7cd43dac7585f {
#[kind(type Of<'a, A: 'a>: 'a;)]
pub trait ParCompactable {
/// Compacts a data structure of [`Option`]s in parallel, discarding [`None`] values and
/// keeping [`Some`] values.
///
Expand Down
3 changes: 2 additions & 1 deletion fp-library/src/classes/par_foldable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ mod inner {
/// let result: String = par_fold_map::<VecBrand, _, _>(|x: i32| x.to_string(), v);
/// assert_eq!(result, "12345");
/// ```
pub trait ParFoldable: Kind_cdc7cd43dac7585f {
#[kind(type Of<'a, A: 'a>: 'a;)]
pub trait ParFoldable {
/// Maps each element to a [`Monoid`] value and combines them in parallel.
///
/// Maps each element using `f`, then reduces the results using
Expand Down
3 changes: 2 additions & 1 deletion fp-library/src/classes/par_functor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ mod inner {
/// par_map::<VecBrand, _, _>(f, par_map::<VecBrand, _, _>(g, xs)),
/// );
/// ```
pub trait ParFunctor: Kind_cdc7cd43dac7585f {
#[kind(type Of<'a, A: 'a>: 'a;)]
pub trait ParFunctor {
/// Maps a function over a data structure in parallel.
///
/// When the `rayon` feature is enabled, elements are processed across multiple threads.
Expand Down
3 changes: 2 additions & 1 deletion fp-library/src/classes/pointed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ mod inner {
};

/// A type class for contexts that can be initialized with a value.
pub trait Pointed: Kind_cdc7cd43dac7585f {
#[kind(type Of<'a, A: 'a>: 'a;)]
pub trait Pointed {
/// The value wrapped in the context.
///
/// This method wraps a value in a context.
Expand Down
8 changes: 5 additions & 3 deletions fp-library/src/classes/profunctor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,10 @@ mod inner {
/// ### Hierarchy Unification
///
/// This trait is now the root of the unified profunctor and arrow hierarchies on
/// [`Kind_266801a817966495`]. This unification ensures that all profunctor-based abstractions
/// [`Kind!(type Of<'a, A: 'a, B: 'a>: 'a;)`](crate::kinds::Kind_266801a817966495).
/// This unification ensures that all profunctor-based abstractions
/// (including lenses and prisms) share a consistent higher-kinded representation with
/// strict lifetime bounds (`type Of<'a, T: 'a, U: 'a>: 'a;`).
/// strict lifetime bounds.
///
/// By explicitly requiring that both type parameters outlive the application lifetime `'a`,
/// we provide the compiler with the necessary guarantees to handle trait objects
Expand Down Expand Up @@ -103,7 +104,8 @@ mod inner {
/// assert_eq!(left(5), right(5));
/// assert_eq!(left(0), right(0));
/// ```
pub trait Profunctor: Kind_266801a817966495 {
#[kind(type Of<'a, A: 'a, B: 'a>: 'a;)]
pub trait Profunctor {
/// Maps over both arguments of the profunctor.
///
/// This method applies a contravariant function to the first argument and a covariant
Expand Down
2 changes: 1 addition & 1 deletion fp-library/src/classes/profunctor/choice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ mod inner {
///
/// ### Hierarchy Unification
///
/// This trait uses the strict Kind signature from [`Kind_266801a817966495`]. This ensures
/// This trait uses the strict Kind signature from [`Kind!(type Of<'a, A: 'a, B: 'a>: 'a;)`](crate::kinds::Kind_266801a817966495). This ensures
/// that when lifting a profunctor, the alternative variants of the sum type correctly
/// satisfy lifetime requirements relative to the profunctor's application.
///
Expand Down
2 changes: 1 addition & 1 deletion fp-library/src/classes/profunctor/strong.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ mod inner {
///
/// ### Hierarchy Unification
///
/// This trait uses the strict Kind signature from [`Kind_266801a817966495`]. This ensures
/// This trait uses the strict Kind signature from [`Kind!(type Of<'a, A: 'a, B: 'a>: 'a;)`](crate::kinds::Kind_266801a817966495). This ensures
/// that when lifting a profunctor, the secondary component of the product type (the context)
/// correctly satisfies lifetime requirements relative to the profunctor's application.
///
Expand Down
3 changes: 2 additions & 1 deletion fp-library/src/classes/ref_functor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ mod inner {
///
/// This is a variant of `Functor` for types where `map` receives/returns references.
/// This is required for types like `Lazy` where `get()` returns `&A`, not `A`.
pub trait RefFunctor: Kind_cdc7cd43dac7585f {
#[kind(type Of<'a, A: 'a>: 'a;)]
pub trait RefFunctor {
/// Maps a function over the values in the functor context, where the function takes a reference.
#[document_signature]
///
Expand Down
Loading
Loading