### Val/Ref Dispatch
The library has two parallel type class hierarchies: a **by-value** hierarchy
(`Functor`, `Semimonad`, `Foldable`, etc.) where closures receive owned values,
and a **by-reference** hierarchy (`RefFunctor`, `RefSemimonad`, `RefFoldable`,
etc.) where closures receive borrowed references. This split exists because
memoized types like `Lazy` can only lend references to their cached values,
not give up ownership (see [Limitations](./limitations-and-workarounds.md)).
Rather than exposing two separate functions per operation (`map` and `ref_map`),
the dispatch system provides a **single unified function** that routes to the
correct trait based on the closure's argument type:
```rust
use fp_library::functions::*;
// Closure takes i32 (owned) -> dispatches to Functor::map
// Closure takes &i32 (borrowed) -> dispatches to RefFunctor::ref_map
let v = vec![1, 2, 3];
1. The closure type `Fn(i32) -> i32` matches the Val impl (takes owned `A`).
2. The compiler infers `Marker = Val` and `FA = Option<i32>`.
3. `dispatch` delegates to `Functor::map`.
When the caller writes `map(|x: &i32| *x + 10, &v)`:
1. The closure type `Fn(&i32) -> i32` matches the Ref impl (takes `&A`).
2. The compiler infers `Marker = Ref` and `FA = &Vec<i32>`.
3. `dispatch` delegates to `RefFunctor::ref_map`.
The `FA` type parameter is key: it appears in both the dispatch trait (to
constrain the container) and in `InferableBrand` (to resolve the brand).
This is how dispatch and brand inference compose through a single type variable.
See [Brand Inference](./brand-inference.md) for how the reverse mapping from
concrete types to brands works.
#### Closureless dispatch
Functions that take no closure (`alt`, `compact`, `separate`, `join`,
`apply_first`, `apply_second`) use a variant where the **container type**
itself drives dispatch instead of a closure's argument type. Owned containers
resolve to `Val`, borrowed containers resolve to `Ref`:
```rust
use fp_library::functions::*;
// Owned containers -> Alt::alt
let y = alt(None, Some(5));
assert_eq!(y, Some(5));
// Borrowed containers -> RefAlt::ref_alt
let a = vec![1, 2];
let b = vec![3, 4];
let y = alt(&a, &b);
assert_eq!(y, vec![1, 2, 3, 4]);
```
#### Module structure
The dispatch system lives in `fp-library/src/dispatch/`, with one file per
type class operation mirroring `classes/`. Each dispatch module contains
the dispatch trait, Val/Ref impl blocks, the inference wrapper function,
and an `explicit` submodule with the brand-explicit variant:
```text
classes/functor.rs -> Functor trait (by-value map)
classes/ref_functor.rs -> RefFunctor trait (by-ref map)
dispatch/functor.rs -> pub(crate) mod inner {
FunctorDispatch trait,
Val impl (Fn(A) -> B -> Functor::map),
Ref impl (Fn(&A) -> B -> RefFunctor::ref_map),
pub fn map (inference wrapper),
pub mod explicit { pub fn map (Brand turbofish) },
}
functions.rs -> Re-exports: map (inference), explicit::map (dispatch)
```
The `functions.rs` module re-exports inference wrappers from
`crate::dispatch::*` and explicit functions from
`crate::dispatch::*/explicit::*`. There are no intermediate
`functions/*.rs` source files.
#### Relationship to thread safety and parallelism
The Val/Ref split is orthogonal to thread safety. The library has separate
`Send*` and `Par*` trait hierarchies that add `Send + Sync` bounds for
concurrent use. These axes combine independently: a type can implement
`RefFunctor` (by-ref, thread-local), `SendRefFunctor` (by-ref, thread-safe),
`ParRefFunctor` (by-ref, parallel), etc. See [Thread Safety and Parallelism](./parallelism.md)
for details on the thread-safe and parallel trait hierarchies.