fp-library 0.17.0

A functional programming library for Rust featuring your favourite higher-kinded types and type classes.
Documentation
### Brand Inference

The library's HKT encoding provides a **forward mapping** from brands to concrete types
(`OptionBrand` -> `Option<A>`), but the compiler has no way to go backwards: given
`Option<A>`, it cannot determine that `OptionBrand` is the right brand. This means
every free function call would require a turbofish annotation:

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

// Without brand inference, the brand must be specified explicitly
let y = map::<OptionBrand, _, _, _, _>(|x: i32| x + 1, Some(5));
```

Brand inference adds the **reverse mapping** (concrete type -> brand), letting the
compiler infer the brand automatically:

```rust
use fp_library::functions::*;

// Brand inferred from Option<i32>
let y = map(|x: i32| x + 1, Some(5));
assert_eq!(y, Some(6));
```

#### How it works

For each `Kind` trait generated by `trait_kind!`, a corresponding
`InferableBrand` trait is also generated. `InferableBrand` takes `Brand`
as a trait parameter (not an associated type), so a single concrete type
can implement it multiple times, once per brand. This is what enables
multi-brand inference for types like `Result`. The trait also carries a
`Marker` associated type (`Val` or `Ref`) that the dispatch system uses
to route to the correct trait method.

When `impl_kind!` defines a brand, it generates both the forward `Kind`
impl (brand -> concrete type) and the reverse `InferableBrand` impl
(concrete type -> brand). The inference wrapper for `map` (and similar
operations) uses `InferableBrand` bounds on the container type `FA` to
resolve the brand automatically.

For the full trait shapes, impl landscape, and Marker invariant, see
[Brand Dispatch Traits](./brand-dispatch-traits.md).

When the caller writes `map(|x| x + 1, Some(5))`, the compiler infers
`FA = Option<i32>`, finds the matching `InferableBrand` impl to resolve
`Brand = OptionBrand` and `Marker = Val`, then selects the correct
dispatch impl. Borrowed containers work the same way via a blanket
`&T` impl that sets `Marker = Ref`. See the
[inference resolution steps](./brand-dispatch-traits.md#how-closure-directed-inference-resolves-brand)
in Brand Dispatch Traits for a detailed walkthrough.

#### Multi-brand types

Some types are reachable through multiple brands at a given arity.
`Result<A, E>` has both `ResultErrAppliedBrand<E>` and
`ResultOkAppliedBrand<A>` as arity-1 brands. Each brand gets its own
`InferableBrand` impl, generated by a separate `impl_kind!` invocation.
See the [impl landscape](./brand-dispatch-traits.md#impl-landscape) in
Brand Dispatch Traits for the full impl details.

Closure-directed inference disambiguates which brand applies. When the
closure's input type is annotated, it pins the `A` type parameter, which
in turn selects a unique `InferableBrand` impl:

- `map(|x: i32| x + 1, Ok::<i32, String>(5))` pins `A = i32`, selecting
  `ResultErrAppliedBrand<String>` (maps over Ok values).
- `map(|e: String| e.len(), Err::<i32, String>("hi".into()))` pins
  `A = String`, selecting `ResultOkAppliedBrand<i32>` (maps over Err values).

For diagonal cases where both brands unify (e.g., `Result<T, T>`), the
closure cannot disambiguate and the compiler reports an ambiguity error.
Use [`explicit::map`](crate::functions::explicit::map) with a turbofish in
these cases.

At arity 2, `Result` has exactly one brand (`ResultBrand`), so
`bimap((f, g), Ok(5))` infers the brand without annotation. The ambiguity
is arity-specific, not type-specific.

#### The `#[multi_brand]` attribute

The `#[multi_brand]` attribute on `impl_kind!` is a documentation marker,
not a codegen switch. It signals to human readers that a brand shares its
target type with other brands. See the
[`#[multi_brand]` section](./brand-dispatch-traits.md#relationship-to-multi_brand)
in Brand Dispatch Traits for the full explanation.

#### Known limitations

- `'static` bounds on multi-brand `InferableBrand` impls prevent non-static
  fixed parameters from using inference. For example, if `E` has a lifetime,
  `map(f, Ok::<i32, &str>(5))` works because `&str: 'static`, but a
  non-static reference type would require `explicit::map`.
- `&&T` (double reference) is not supported by `FunctorDispatch`'s `Ref`
  impl. Pass a single reference (`&T`) instead.
- Pre-bound closures (`let f = |x| x + 1; map(f, Ok(5))`) may lose deferred
  inference context for multi-brand types, because the closure's parameter
  type is committed before `map` can use it for brand resolution. Annotate
  the closure parameter type explicitly in these cases.
- `trait_kind!` and `impl_kind!` emit `::fp_library::dispatch::{Val, Ref}`
  in generated code. External crates must depend on `fp-library` for the
  macros to work correctly.

#### Relationship to Val/Ref dispatch

Brand inference determines _which type constructor_ to use; [Val/Ref dispatch](./dispatch.md)
determines _which trait method_ (by-value or by-reference) to call. The two
systems compose through the shared `FA` type parameter: brand inference resolves
`FA` to a brand, while dispatch resolves `FA`'s ownership to a `Val` or `Ref`
marker. Together they enable fully inferred calls like `map(|x: i32| x + 1, Some(5))`
with no turbofish and no explicit val/ref selection.