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
43 changes: 27 additions & 16 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,29 @@ All shell commands must be prefixed with `eval "$(direnv export bash 2>/dev/null

## Development Commands

### Formatting & Linting

```bash
# Format code (uses rustfmt.toml configuration)
eval "$(direnv export bash 2>/dev/null)"; cargo fmt --all

# Check formatting
eval "$(direnv export bash 2>/dev/null)"; cargo fmt --all -- --check

# Run clippy
eval "$(direnv export bash 2>/dev/null)"; cargo clippy --workspace --all-features
```

### Documentation

```bash
# Check documentation (must produce zero warnings)
eval "$(direnv export bash 2>/dev/null)"; cargo doc --workspace --all-features --no-deps

# Build and open documentation
eval "$(direnv export bash 2>/dev/null)"; cargo doc --workspace --all-features --open
```

### Testing

```bash
Expand Down Expand Up @@ -67,27 +90,15 @@ eval "$(direnv export bash 2>/dev/null)"; cargo bench -p fp-library --bench benc
# Benchmark reports are generated in target/criterion/report/index.html
```

### Formatting & Linting
### Verification

After making changes, always verify in this order: **fmt → clippy → doc → test**.

```bash
# Format code (uses rustfmt.toml configuration)
eval "$(direnv export bash 2>/dev/null)"; cargo fmt --all

# Check formatting
eval "$(direnv export bash 2>/dev/null)"; cargo fmt --all -- --check

# Run clippy
eval "$(direnv export bash 2>/dev/null)"; cargo clippy --workspace --all-features
```

### Documentation

```bash
# Build and open documentation
eval "$(direnv export bash 2>/dev/null)"; cargo doc --workspace --all-features --open

# Check documentation
eval "$(direnv export bash 2>/dev/null)"; cargo doc --workspace --all-features --no-deps
eval "$(direnv export bash 2>/dev/null)"; cargo test --workspace --all-features
```

## Language Server & Code Intelligence
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.

50 changes: 43 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,22 @@ A functional programming library for Rust featuring your favourite higher-kinded
## Features

- **Higher-Kinded Types (HKT):** Implemented using lightweight higher-kinded polymorphism (type-level defunctionalization/brands).
- **Macros:** Procedural macros (`trait_kind!`, `impl_kind!`, `Apply!`) to simplify HKT boilerplate and type application.
- **Macros:** Procedural macros for working with HKTs and monadic code:
- **HKT:** `trait_kind!`, `impl_kind!`, `Apply!` 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`, `Applicative`, `Monad`, `Semigroup`, `Monoid`, `Foldable`, `Traversable`
- **Core:** `Functor`, `Contravariant`, `Pointed`, `Applicative`, `Semiapplicative`, `Monad`, `Semimonad`, `Semigroup`, `Monoid`, `Foldable`, `Traversable`, `Alt`, `Plus`, `Alternative`
- **Applicative Utilities:** `Lift`, `ApplyFirst`, `ApplySecond`
- **Monad Utilities:** `MonadRec`, `Evaluable`
- **Bifunctors:** `Bifunctor`, `Bifoldable`, `Bitraversable`
- **Collections:** `Compactable`, `Filterable`, `Witherable`
- **Indexed:** `FunctorWithIndex`, `FoldableWithIndex`, `TraversableWithIndex`
- **Category Theory:** `Category`, `Semigroupoid`, `Profunctor`, `Strong`, `Choice`, `Closed`, `Cochoice`, `Costrong`, `Wander`
- **Utilities:** `Pointed`, `Lift`, `ApplyFirst`, `ApplySecond`, `Semiapplicative`, `Semimonad`, `Contravariant`, `Evaluable`
- **Advanced/Internal:** `MonadRec`, `RefFunctor`, `Deferrable`, `SendDeferrable`
- **Function & Pointer Abstractions:** `Function`, `CloneableFn`, `SendCloneableFn`, `UnsizedCoercible`, `SendUnsizedCoercible`, `ParFoldable`, `Pointer`, `RefCountedPointer`, `SendRefCountedPointer`
- **Laziness & Effects:** `RefFunctor`, `Deferrable`, `SendDeferrable`
- **Function & Pointer Abstractions:** Traits for abstracting over function wrappers and reference counting:
- **Functions:** `Function`, `CloneableFn`, `SendCloneableFn`, `UnsizedCoercible`, `SendUnsizedCoercible`
- **Pointers:** `Pointer`, `RefCountedPointer`, `SendRefCountedPointer`
- **Parallel:** `ParFoldable`
- **Optics:** Composable data accessors using profunctor encoding (port of PureScript's `purescript-profunctor-lenses`):
- **Iso / IsoPrime:** Isomorphism between two types
- **Lens / LensPrime:** Focus on a field within a product type
Expand All @@ -32,8 +38,10 @@ A functional programming library for Rust featuring your favourite higher-kinded
- **Grate / GratePrime:** Closed/zipping optics
- **Indexed variants:** `IndexedLens`, `IndexedTraversal`, `IndexedGetter`, `IndexedFold`, `IndexedSetter`
- **Composition:** `Composed` struct and `optics_compose` for zero-cost optic composition
- **Numeric Algebra:** `Semiring`, `Ring`, `CommutativeRing`, `EuclideanRing`, `DivisionRing`, `Field`, `HeytingAlgebra`
- **Newtype Wrappers:** `Additive`, `Multiplicative`, `Conjunctive`, `Disjunctive`, `First`, `Last`, `Dual`
- **Helper Functions:** Standard FP utilities:
- `compose`, `constant`, `flip`, `identity`
- `compose`, `constant`, `flip`, `identity`, `on`
- **Data Types:** Implementations for standard and custom types:
- **Standard Library:** `Option`, `Result`, `Vec`, `String`
- **Laziness, Memoization & Stack Safety:** `Lazy` (`RcLazy`, `ArcLazy`), `Thunk`, `Trampoline`, `Free`
Expand All @@ -58,7 +66,7 @@ Add `fp-library` to your `Cargo.toml`:

```toml
[dependencies]
fp-library = "0.11"
fp-library = "0.12"
```

### Crate Features
Expand Down Expand Up @@ -92,6 +100,34 @@ fn main() {
}
```

### Example: Monadic Do-Notation with `m_do!`

The `m_do!` macro provides Haskell/PureScript-style do-notation for flat monadic code.
It desugars `<-` binds into nested `bind` calls.

```rust
use fp_library::{brands::*, functions::*};
use fp_macros::m_do;

fn main() {
let result = m_do!(OptionBrand {
x <- Some(5);
y <- Some(x + 1);
let z = x * y;
pure(z)
});
assert_eq!(result, Some(30));

// Works with any monad brand
let result = m_do!(VecBrand {
x <- vec![1, 2];
y <- vec![10, 20];
pure(x + y)
});
assert_eq!(result, vec![11, 21, 12, 22]);
}
```

## How it Works

### Higher-Kinded Types (HKT)
Expand Down
49 changes: 23 additions & 26 deletions docs/release-process.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,7 @@ This document outlines the steps for releasing new versions of `fp-library` and

## Release Steps

### 1. Create a Release Branch

```bash
git checkout -b release/fp-library-vX.Y.Z
```

### 2. Determine Version Bump

Follow [Semantic Versioning](https://semver.org/), with the following policy for pre-1.0.0 releases:

- **Major** (X.0.0): Reserved for when the API is declared stable.
- **Minor** (0.X.0): Incompatible API changes or significant new functionality.
- **Patch** (0.0.X): Backwards-compatible bug fixes or minor additions.

### 3. Update Changelogs

Update `fp-library/CHANGELOG.md` and `fp-macros/CHANGELOG.md` (if applicable).

#### Determining changelog content
### 1. Review Changes Since Last Release

For each package being released, determine what has changed since the last release:

Expand Down Expand Up @@ -63,13 +45,28 @@ For each package being released, determine what has changed since the last relea

Use the commit messages (especially conventional commit prefixes like `feat:`, `fix:`, `refactor:`) as a guide, but always verify against the actual diff to ensure nothing is missed or mischaracterized.

#### Writing the changelog entry
Record the categorized changes under the `[Unreleased]` section of `fp-library/CHANGELOG.md` and `fp-macros/CHANGELOG.md` (if applicable).

### 2. Determine Version Bump

Based on the changes identified above, follow [Semantic Versioning](https://semver.org/) with the following policy for pre-1.0.0 releases:

- **Major** (X.0.0): Reserved for when the API is declared stable.
- **Minor** (0.X.0): Incompatible API changes or significant new functionality.
- **Patch** (0.0.X): Backwards-compatible bug fixes or minor additions.

### 3. Create a Release Branch

```bash
git checkout -b release/fp-library-vX.Y.Z
```

### 4. Finalize Changelogs

1. Rename the `[Unreleased]` section to the new version number and date (e.g., `[0.3.0] - 2026-01-16`).
2. List all notable changes under the appropriate headers (Added, Changed, Removed, Fixed).
3. Create a new empty `[Unreleased]` section at the top.
2. Create a new empty `[Unreleased]` section at the top.

### 4. Update Cargo.toml
### 5. Update Cargo.toml

#### fp-macros (if changed)

Expand All @@ -80,7 +77,7 @@ For each package being released, determine what has changed since the last relea
1. Update `version` in `fp-library/Cargo.toml` and in `README.md`.
2. If `fp-macros` was updated, ensure the `fp-macros` dependency in `fp-library/Cargo.toml` matches the new version.

### 5. Verification
### 6. Verification

Run the full suite of checks locally to catch issues before the PR:

Expand All @@ -98,7 +95,7 @@ cargo clippy
cargo doc --open
```

### 6. Commit and Open PR
### 7. Commit and Open PR

1. Stage and commit the release changes:

Expand All @@ -121,7 +118,7 @@ cargo doc --open
- **Squash and Merge** is preferred to keep the `main` branch history clean and linear.
- **Conventional Commits** are encouraged for PR titles/squash commits (e.g., `feat:`, `fix:`, `chore:`, `refactor:`, `docs:`, etc.).

### 7. Tag and Publish
### 8. Tag and Publish

After the PR is merged, tag the release on `main`:

Expand Down
7 changes: 4 additions & 3 deletions docs/todo.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

* Optics: Implement missing functionality from [analysis](optics-analysis.md).
* Algebraic effects/effect system to implement extensible effects
* [Analysis](../plans/effects/effects.md)
* [Eff](https://github.com/lexi-lambda/eff) [documentation](https://hasura.github.io/eff/Control-Effect.html)
* `Alternative` type class (requires `Plus` and `Applicative`).
* Kleisli composition (`compose_kleisli`, `>=>` equivalent). Composes monadic functions `A -> F<B>` and `B -> F<C>` into `A -> F<C>` without explicit `bind` threading. Enables point-free monadic pipelines and reusable monadic function building blocks.
* `do!` macro. Desugars sequential monadic binds from flat syntax into nested `bind` calls, e.g. `do! { x <- fa; y <- g(x); pure(x + y) }` becomes `bind(fa, |x| bind(g(x), |y| pure(x + y)))`. Eliminates rightward drift from deeply nested closures.
* `Extend` and `Comonad` type classes (dual of `Monad`).
* `MonadZero` and `MonadPlus` type classes.
* Inline `!`-notation within `m_do!`: allow `m_do! { pure(!fa + !fb) }` as shorthand that automatically lifts subexpressions into binds, similar to Idris's `!`-notation. Avoids unnecessary intermediate bindings when a value is used once, immediately. Implement as an incremental enhancement to `m_do!` rather than a standalone feature.
* Property-based tests for type class laws.
* [Validity](https://github.com/NorfairKing/validity).
* Add a diagram of the typeclass/trait hierarchy and reasoning/justification for why the current hierarchy is as it is.
Expand Down
21 changes: 21 additions & 0 deletions fp-library/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.12.0] - 2026-03-13

### Added
- **`Alt` / `Plus` / `Alternative` type classes**: Associative choice (`alt`), identity for choice (`plus_empty`), and `Alternative` (blanket impl for `Applicative + Plus`). Implementations for `Option`, `Vec`, `CatList`.
- **Numeric algebra hierarchy**: `Semiring`, `Ring`, `CommutativeRing`, `EuclideanRing` (with `gcd`/`lcm`), `DivisionRing`, `Field`, `HeytingAlgebra`. Instances for all Rust numeric primitives and `bool`. Integer instances use wrapping arithmetic.
- **Monoid newtype wrappers**: `Additive`, `Multiplicative`, `Conjunctive`, `Disjunctive`, `First`, `Last`, `Dual` with `Semigroup`/`Monoid` instances.
- **`Semimonad` derived combinators**: `bind_flipped`, `join`, `compose_kleisli`, `compose_kleisli_flipped`.
- **`Monad` derived combinators**: `if_m`, `when_m`, `unless_m`.
- **`Applicative` combinators**: `when`, `unless`.
- **`Monoid` combinator**: `power` (binary exponentiation via repeated `append`).
- **`Lift` functions**: `lift3`, `lift4`, `lift5` for higher-arity lifting via nested `lift2`.
- **`on` function**: Apply a binary function after projecting both arguments (`on(f, g, x, y) = f(g(x), g(y))`).
- **Law-checking doc examples** across 22 type class traits: `Applicative`, `Bifunctor`, `Bifoldable`, `Bitraversable`, `Category`, `Choice`, `Compactable`, `Contravariant`, `Filterable`, `Foldable`, `FoldableWithIndex`, `Functor`, `FunctorWithIndex`, `Monad`, `Monoid`, `Semiapplicative`, `Semigroup`, `Semigroupoid`, `Strong`, `Traversable`, `TraversableWithIndex`, `Witherable`.

### Changed
- Updated doc examples and imports to use renamed `m_do!`/`a_do!` macros (from `m!`/`ado!`).

### Fixed
- Profunctor composition law: corrected `g` argument order.
- 15 broken rustdoc links in newtype wrapper module docs.

## [0.11.1] - 2026-03-10

### 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.11.1"
version = "0.12.0"
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.4" }
fp-macros = { path = "../fp-macros", version = "0.5" }
rayon = { version = "1.11", optional = true }
serde = { version = "1.0", optional = true, features = ["derive"] }
thiserror = "2.0"
Expand Down
10 changes: 10 additions & 0 deletions fp-library/src/classes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
//! assert_eq!(y, Some(10));
//! ```

pub mod alt;
pub mod alternative;
pub mod applicative;
pub mod apply_first;
pub mod apply_second;
Expand All @@ -26,32 +28,40 @@ pub mod bifunctor;
pub mod bitraversable;
pub mod category;
pub mod cloneable_fn;
pub mod commutative_ring;
pub mod compactable;
pub mod contravariant;
pub mod deferrable;
pub mod division_ring;
pub mod euclidean_ring;
pub mod evaluable;
pub mod field;
pub mod filterable;
pub mod foldable;
pub mod foldable_with_index;
pub mod function;
pub mod functor;
pub mod functor_with_index;
pub mod heyting_algebra;
pub mod lift;
pub mod monad;
pub mod monad_rec;
pub mod monoid;
pub mod optics;
pub mod par_foldable;
pub mod pipe;
pub mod plus;
pub mod pointed;
pub mod pointer;
pub mod profunctor;
pub mod ref_counted_pointer;
pub mod ref_functor;
pub mod ring;
pub mod semiapplicative;
pub mod semigroup;
pub mod semigroupoid;
pub mod semimonad;
pub mod semiring;
pub mod send_cloneable_fn;
pub mod send_deferrable;
pub mod send_ref_counted_pointer;
Expand Down
Loading
Loading