# Functype Feature Matrix

This matrix shows which interfaces are supported by each data structure in the functype library.

## Legend

- ✓ Full support
- ◐ Partial support (custom implementation)
- ✗ Not supported
- ← Inherited from parent interface

## Core Interfaces

| Data Structure     | Functor | Applicative | Monad | AsyncMonad | Foldable | Matchable | Serializable | Traversable | Extractable | Unsafe | Pipe | Collection | ContainerOps | CollectionOps |
| ------------------ | :-----: | :---------: | :---: | :--------: | :------: | :-------: | :----------: | :---------: | :---------: | :----: | :--: | :--------: | :----------: | :-----------: |
| **Option<T>**      |    ✓    |      ✓      |   ✓   |     ✓      |    ✓     |     ✓     |      ✓       |      ✓      |      ✓      |   ←    |  ✓   |     ✗      |      ✓       |       ✗       |
| **Either<L,R>**    |    ✓    |      ✓      |   ✓   |     ✓      |    ✓     |     ✗     |      ✓       |      ✗      |      ✓      |   ←    |  ✗   |     ✗      |      ◐       |       ✗       |
| **Try<T>**         |    ✓    |      ✓      |   ✓   |     ✓      |    ✓     |     ✗     |      ✓       |      ✗      |      ✓      |   ←    |  ✓   |     ✗      |      ◐       |       ✗       |
| **IO<R,E,A>**      |    ✓    |      ✓      |   ✓   |     ✓      |    ✓     |     ✓     |      ✗       |      ✗      |      ✗      |   ✗    |  ✓   |     ✗      |      ✗       |       ✗       |
| **Http**           |    ✗    |      ✗      |   ✗   |     ✗      |    ✗     |     ✗     |      ✗       |      ✗      |      ✗      |   ✗    |  ✗   |     ✗      |      ✗       |       ✗       |
| **TaskOutcome<T>** |    ✓    |      ✓      |   ✓   |     ✓      |    ✓     |     ✗     |      ✓       |      ✓      |      ✓      |   ←    |  ✓   |     ✗      |      ✓       |       ✗       |
| **List<A>**        |    ✓    |      ✓      |   ✓   |     ✓      |    ✓     |     ✗     |      ✓       |      ✓      |      ✗      |   ✗    |  ✓   |     ✓      |      ✓       |       ✓       |
| **Set<A>**         |    ✓    |      ✓      |   ✓   |     ✓      |    ✓     |     ✗     |      ✓       |      ✓      |      ✗      |   ✗    |  ✓   |     ✓      |      ✓       |       ✓       |
| **Obj<T>**         |    ◐    |      ◐      |   ◐   |     ◐      |    ✓     |     ✓     |      ✓       |      ◐      |      ✓      |   ←    |  ✓   |     ✗      |      ✓       |       ✗       |
| **Map<K,V>**       |    ◐    |      ✗      |   ✗   |     ✗      |    ✓     |     ✗     |      ✓       |      ◐      |      ✗      |   ✗    |  ✓   |     ✓      |      ✗       |       ✗       |
| **Lazy<T>**        |    ✓    |      ✓      |   ✓   |     ✓      |    ✓     |     ✗     |      ✓       |      ✓      |      ✓      |   ←    |  ✓   |     ✗      |      ✓       |       ✗       |
| **Stack<A>**       |    ✗    |      ✗      |   ✗   |     ✗      |    ✓     |     ✓     |      ✓       |      ✓      |      ✗      |   ✗    |  ✓   |     ✗      |      ✗       |       ✗       |
| **LazyList<A>**    |    ◐    |      ✗      |   ◐   |     ✗      |    ✓     |     ✗     |      ✓       |      ✗      |      ✗      |   ✗    |  ✓   |     ✗      |      ✗       |       ✗       |
| **Tuple<T[]>**     |    ◐    |      ✗      |   ◐   |     ✗      |    ✓     |     ✗     |      ✓       |      ✗      |      ✗      |   ✗    |  ✓   |     ✗      |      ✗       |       ✗       |

## Variance (0.6.0+)

| Data Structure     | Variance                   | Notes                                                                                                                                    |
| ------------------ | :------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **Option<T>**      | `<out T>`                  | covariant                                                                                                                                |
| **Either<L,R>**    | `<out L, out R>`           | covariant in both                                                                                                                        |
| **Try<T>**         | `<out T>`                  | covariant                                                                                                                                |
| **List<A>**        | `<out A>`                  | covariant. `contains`/`remove`/`indexOf` accept `unknown`; `add`/`prepend`/`concat` widen to `A \| B`; `reduce` guarded by `Widen<A, B>` |
| **Set<A>**         | `<out A>`                  | covariant. Same patterns as List                                                                                                         |
| **LazyList<A>**    | `<out A>`                  | covariant. `concat<B>` widens                                                                                                            |
| **Lazy<T>**        | `<out T>`                  | covariant                                                                                                                                |
| **Identity<T>**    | `<out T>`                  | covariant. `isSame` accepts `Identity<unknown>`                                                                                          |
| **Tuple<T[]>**     | `<out T>`                  | covariant                                                                                                                                |
| **Map<K,V>**       | `<K, out V>`               | V covariant; K invariant (Scala Map[K, +V] precedent — equality-sensitive keys)                                                          |
| **TaskOutcome<T>** | `<out T>`                  | covariant. `recover<U>` / `recoverWith<U>` widen to `Ok<T \| U>`                                                                         |
| **Stack<A>**       | structural covariant       | intersection type alias can't carry `<out>`; subtyping works structurally                                                                |
| **Obj<T>**         | invariant (by design)      | T is a record type; `keyof T` is contravariant, so widening loses key fidelity                                                           |
| **Ref<A>**         | invariant (by design)      | mutable cell; `set(A)` writes A, widening would be unsound                                                                               |
| **IO<R,E,A>**      | `<in out R, out E, out A>` | E and A covariant; R invariant. `IO<R, never, A>` widens to `IO<R, AnyError, A>` without a cast. ZIO-style `<in R>` still deferred.      |

All base typeclasses (`Traversable`, `Extractable`, `Functor`, `Applicative`, `Monad`, `AsyncMonad`, `ContainerOps`, `CollectionOps`, `Foldable`, `Serializable`, `Pipe`, `Matchable`, `Promisable`, `Doable`, `Reshapeable`) declared `<out T>` / `<out A>`.

`Traversable.reduce` / `reduceRight` are guarded by `Widen<A, B>` (`src/typeclass/variance.ts`), TypeScript's equivalent of Scala's `[B >: A]` lower-bound constraint. See [`variance-guide.md`](./variance-guide.md) for the full contributor reference.

Collections (`List`, `Set`, `LazyList`, `Stack`, `Map`, `Obj`) keep `Traversable`. Sum types (`Either`, `Try`) extend the lighter `FunctypeSum` base with no collection-style methods.

## Additional Properties

| Data Structure     | Typeable | Valuable | Iterable | PromiseLike | Do-notation | Reshapeable | Promisable |
| ------------------ | :------: | :------: | :------: | :---------: | :---------: | :---------: | :--------: |
| **Option<T>**      |    ✓     |    ✗     |    ✗     |      ✗      |      ✓      |      ✓      |     ✓      |
| **Either<L,R>**    |    ✓     |    ✗     |    ✗     |      ✓      |      ✓      |      ✓      |     ✓      |
| **Try<T>**         |    ✓     |    ✗     |    ✗     |      ✗      |      ✓      |      ✓      |     ✓      |
| **IO<R,E,A>**      |    ✗     |    ✗     |    ✓     |      ✗      |      ✓      |      ✗      |     ✗      |
| **Http**           |    ✗     |    ✗     |    ✗     |      ✗      |      ✗      |      ✗      |     ✗      |
| **List<A>**        |    ✓     |    ✗     |    ✓     |      ✗      |      ✓      |      ✓      |     ✗      |
| **Set<A>**         |    ✓     |    ✗     |    ✓     |      ✗      |      ✗      |      ✗      |     ✗      |
| **Obj<T>**         |    ✓     |    ✗     |    ✗     |      ✗      |      ✓      |      ✓      |     ✓      |
| **Map<K,V>**       |    ✓     |    ✗     |    ✓     |      ✗      |      ✗      |      ✗      |     ✗      |
| **Lazy<T>**        |    ✓     |    ✗     |    ✗     |      ✗      |      ✗      |      ✗      |     ✗      |
| **Stack<A>**       |    ✓     |    ✓     |    ✗     |      ✗      |      ✗      |      ✗      |     ✗      |
| **LazyList<A>**    |    ✓     |    ✗     |    ✓     |      ✗      |      ✗      |      ✗      |     ✗      |
| **Tuple<T[]>**     |    ✓     |    ✓     |    ✓     |      ✗      |      ✗      |      ✗      |     ✗      |
| **TaskOutcome<T>** |    ✓     |    ✗     |    ✗     |      ✗      |      ✓      |      ✗      |     ✓      |

## Companion Methods

All types follow the **Companion pattern** (inspired by Scala), combining constructor functions with static utility methods. Each type provides:

### Common Creation Methods

| Data Structure  | of  | from | pure | empty | none | left | right | success | failure |
| --------------- | :-: | :--: | :--: | :---: | :--: | :--: | :---: | :-----: | :-----: |
| **Option<T>**   |  ✓  |  ✓   |  ✗   |   ✗   |  ✓   |  ✗   |   ✗   |    ✗    |    ✗    |
| **Either<L,R>** |  ✗  |  ✗   |  ✗   |   ✗   |  ✗   |  ✓   |   ✓   |    ✗    |    ✗    |
| **Try<T>**      |  ✓  |  ✗   |  ✗   |   ✗   |  ✗   |  ✗   |   ✗   |    ✓    |    ✓    |
| **IO<R,E,A>**   |  ✗  |  ✓   |  ✗   |   ✗   |  ✗   |  ✗   |   ✗   |    ✓    |    ✓    |
| **Http**        |  ✗  |  ✗   |  ✗   |   ✗   |  ✗   |  ✗   |   ✗   |    ✗    |    ✗    |
| **List<A>**     |  ✓  |  ✗   |  ✗   |   ✓   |  ✗   |  ✗   |   ✗   |    ✗    |    ✗    |
| **Set<A>**      |  ✓  |  ✗   |  ✗   |   ✓   |  ✗   |  ✗   |   ✗   |    ✗    |    ✗    |
| **Obj<T>**      |  ✓  |  ✗   |  ✗   |   ✓   |  ✗   |  ✗   |   ✗   |    ✗    |    ✗    |
| **Map<K,V>**    |  ✓  |  ✗   |  ✗   |   ✓   |  ✗   |  ✗   |   ✗   |    ✗    |    ✗    |
| **Lazy<T>**     |  ✓  |  ✗   |  ✗   |   ✗   |  ✗   |  ✗   |   ✗   |    ✗    |    ✗    |
| **Stack<A>**    |  ✗  |  ✗   |  ✗   |   ✓   |  ✗   |  ✗   |   ✗   |    ✗    |    ✗    |
| **LazyList<A>** |  ✓  |  ✗   |  ✗   |   ✓   |  ✗   |  ✗   |   ✗   |    ✗    |    ✗    |
| **Tuple<T[]>**  |  ✓  |  ✗   |  ✗   |   ✗   |  ✗   |  ✗   |   ✗   |    ✗    |    ✗    |
| **Identity<T>** |  ✓  |  ✗   |  ✓   |   ✗   |  ✗   |  ✗   |   ✗   |    ✗    |    ✗    |
| **Ref<A>**      |  ✓  |  ✗   |  ✗   |   ✗   |  ✗   |  ✗   |   ✗   |    ✗    |    ✗    |

**Collection creation** - multiple options available:

```typescript
// List creation
List([1, 2, 3]) // from array
List.of(1, 2, 3) // variadic factory
List.empty<number>() // typed empty list

// Set creation
Set([1, 2, 3]) // from array
Set.of(1, 2, 3) // variadic factory
Set.empty<number>() // typed empty set

// Map creation
Map([
  ["a", 1],
  ["b", 2],
]) // from key-value pairs
Map.of<string, number>(["a", 1], ["b", 2]) // variadic factory
Map.empty<string, number>() // typed empty map
```

### Http Methods

```typescript
// Http — fetch wrapper returning IO<never, HttpError, HttpResponse<unknown>> by default
// Provide a validate function to get typed responses (BYOV: bring your own validator)
Http.get(url, opts?)          // GET → HttpResponse<unknown>
Http.get(url, { validate })   // GET → HttpResponse<T> (T inferred from validate)
Http.post(url, opts?)         // POST with auto JSON body serialization
Http.put(url, opts?)          // PUT
Http.patch(url, opts?)        // PATCH
Http.delete(url, opts?)       // DELETE
Http.request(fullOpts)        // Full control
Http.client(config)           // Create configured client with baseUrl, defaultHeaders, custom fetch, beforeRequest (effectful request transformer)

// Example with validator (works with Zod, TypeBox, Valibot, or manual validators)
Http.get("/api/users", { validate: (data) => z.array(UserSchema).parse(data) })
Http.post("/api/users", { body: { name: "Alice" }, validate: (data) => UserSchema.parse(data) })

// HttpError — three-variant ADT
HttpError.networkError(url, method, cause)
HttpError.httpStatusError(url, method, status, statusText, body)
HttpError.decodeError(url, method, body, cause)
HttpError.match(error, { NetworkError, HttpStatusError, DecodeError })
HttpError.isNetworkError(e) / .isHttpStatusError(e) / .isDecodeError(e)
```

### Validation & Typed Errors

Error-accumulating validation — functype's "Validated" applicative role. `Validation`
collects **all** field errors rather than short-circuiting on the first (unlike
`Either.sequence`, which fails fast). Not a typeclass-grid container, so it lives
here rather than in the interface matrix above (same as `HttpError` / `DecoderError`).

```typescript
// FormValidation<T> — the accumulating result type
type FormValidation<T> = Either<List<TypedError<"VALIDATION_FAILED">>, T>

// TypedError — code-tagged structured error (extends Throwable)
TypedError.validation(field, value, rule)   // → TypedError<"VALIDATION_FAILED">, context { field, value, rule }
TypedError.isTypedError(v) / TypedError.hasCode(e, code)

// Validation — rule DSL + form validator
Validation.rule<T>("min:18" | "email" | "required" | "pattern:..." | "in:a,b" | ...)
Validation.combine(...validators)                 // all must pass (fail-fast per field)
Validation.custom<T>(predicate, message)          // custom per-field rule
Validation.validators.email / .url / .required / .positiveNumber / .nonEmptyString
Validation.form(schema, data)                     // → FormValidation<T>, accumulates every field error

// Validator<T> = (value: unknown) => Either<TypedError<"VALIDATION_FAILED">, T>
// form() is flat/per-field. For cross-field (lo < hi) or dynamic-key (weights.*) checks,
// hand-accumulate TypedError.validation(...) into a List and return the same FormValidation shape.
```

### Type Guards

Static type guards for narrowing types:

| Data Structure  | Type Guard Methods                           |
| --------------- | -------------------------------------------- |
| **Option<T>**   | `isSome(option)`, `isNone(option)`           |
| **Either<L,R>** | `isLeft(either)`, `isRight(either)`          |
| **Try<T>**      | `isSuccess(tryValue)`, `isFailure(tryValue)` |

### Serialization Methods

All Serializable types provide static deserialization methods:

- `fromJSON(json: string): T` - Deserialize from JSON
- `fromYAML(yaml: string): T` - Deserialize from YAML
- `fromBinary(binary: string): T` - Deserialize from base64-encoded binary

**Note**: See `docs/companion-pattern.md` for complete guide on the Companion pattern.

## Key Methods by Interface

### Functor

- `map<B>(f: (value: A) => B): Functor<B>`

### Applicative (extends Functor)

- `ap<B>(ff: Applicative<(value: A) => B>): Applicative<B>`

### Monad (extends Applicative)

- `flatMap<B>(f: (value: A) => Monad<B>): Monad<B>`

### AsyncMonad (extends Monad)

- `flatMapAsync<B>(f: (value: A) => PromiseLike<AsyncMonad<B>>): PromiseLike<AsyncMonad<B>>`

### Foldable

- `foldLeft<B>(z: B): (op: (b: B, a: A) => B) => B`
- `foldRight<B>(z: B): (op: (a: A, b: B) => B) => B`

Note: `fold` has different semantics per type category:

- **Sum types** (Option, Either, Try, IO, TaskOutcome): `fold<B>(onEmpty: () => B, onValue: (value: A) => B): B` — pattern match
- **Collections** (List, Set, Map, Stack, Tuple, LazyList): `fold<B>(initial: B, fn: (acc: B, a: A) => B): B` — left-reduce accumulator

`foldAsync` (Option, Either, Try) — same shape as `fold` but accepts sync or async handlers and always returns `Promise<B>`. Use when at least one branch performs async work to avoid `T | Promise<T>` unions.

### Matchable

- `match<R>(patterns: Record<Tags, (value: A) => R>): R`

### Serializable

- `serialize(): SerializationMethods<T>`
  - `toJSON(): string`
  - `toYAML(): string`
  - `toBinary(): Uint8Array`

### Traversable (extends AsyncMonad)

- `size: number`
- `isEmpty: boolean`
- `contains(value: A): boolean`
- `reduce<B>(f: (acc: B, value: A) => B, initial: B): B`
- `reduceRight<B>(f: (value: A, acc: B) => B, initial: B): B`

### Unsafe

- `orThrow(error?: Error): T`

### Extractable (extends Unsafe)

- `orElse(defaultValue: T): T`
- `or(alternative: Extractable<T>): Extractable<T>`
- `orNull(): T | null`
- `orUndefined(): T | undefined`

### Pipe

- `pipe<U>(f: (value: T) => U): U`

### Collection

- `toList(): List<A>`
- `toSet(): Set<A>`
- `toString(): string`

### ContainerOps

- `count(p: (value: A) => boolean): number`
- `find(p: (value: A) => boolean): A | undefined`
- `exists(p: (value: A) => boolean): boolean`
- `forEach(f: (value: A) => void): void`

### CollectionOps

- `drop(n: number): Self`
- `dropRight(n: number): Self`
- `dropWhile(p: (value: A) => boolean): Self`
- `flatten(): Self`
- `head: A | undefined`
- `headOption: Option<A>`
- `take(n: number): Self`
- `takeWhile(p: (value: A) => boolean): Self`
- `takeRight(n: number): Self`
- `last: A | undefined`
- `lastOption: Option<A>`
- `tail: Self`
- `init: Self`
- `toArray(): A[]`

### List-specific Methods

- `reverse(): List<A>`
- `indexOf(value: A): number`
- `prepend(item: A): List<A>`
- `distinct(): List<A>`
- `sorted(compareFn?): List<A>`
- `sortBy(f, compareFn?): List<A>`
- `zip(other: List<B>): List<[A, B]>`
- `zipWithIndex(): List<[A, number]>`
- `groupBy(f: (a: A) => K): Map<K, List<A>>`
- `partition(p): [List<A>, List<A>]`
- `span(p): [List<A>, List<A>]`
- `slice(start, end): List<A>`

### Do-notation Support

Enables Scala-like for-comprehensions using JavaScript generators:

- `Do(function* () { ... })`: Synchronous monadic comprehensions
- `DoAsync(async function* () { ... })`: Async monadic comprehensions
- `$(monad)`: Helper for type inference with `yield*`

### Reshapeable

Provides type conversion between monadic types:

- `toOption(): Option<T>`
- `toEither<E>(leftValue: E): Either<E, T>`
- `toList(): List<T>`
- `toTry(): Try<T>`

### Promisable

Provides conversion to Promise for async interop:

- `toPromise(): Promise<T>`

## Notes

1. **Functype<A, Tag>**: Implemented by single-value containers (Option, Try, Lazy). Provides full functional programming support.

2. **FunctypeCollection<A, Tag>**: Implemented by collection containers (List, Set). Extends FunctypeBase with collection-specific operations.

3. **Special Cases**:
   - **Either**: Implements FunctypeBase but not full Functype (no Extractable/Matchable)
   - **Map**: Uses KVTraversable (omits map/flatMap/ap from Traversable — key-value containers can't freely transform their type parameter)
   - **Obj**: Immutable object wrapper using KVTraversable. Record-constrained map/flatMap (B must be a Record). Provides fluent ops: get, set, assign, merge, when, omit, pick
   - **Stack**: Implements individual interfaces without FunctypeBase
   - **LazyList**: Lazy evaluation with support for Foldable, Serializable, Pipe, and Typeable interfaces
   - **Tuple**: Enhanced container with Foldable, Serializable, Pipe, Typeable, and Valuable support

4. **Do-notation**: Provides generator-based monadic comprehensions similar to Scala's for-comprehensions. Supports Option, Either, Try, and List with automatic short-circuiting and cartesian products.

5. **Reshapeable**: Enables conversion between different monad types, allowing flexible composition in Do-notation when mixing types.

6. **Promisable**: Provides conversion to Promise for async interoperability. Supported by Option, Either, Try, and TaskOutcome.

7. **Utility Types** (not in matrix):
   - **Cond**: Conditional expression builder
   - **Match**: Pattern matching utility
   - **ValidatedBrand**: Branded types with validation
   - **Task**: Sync/async operation orchestrator returning TaskOutcome<T> with Ok/Err constructors. Includes conversion methods: toEither(), toTry(), toOption(), fromEither(), fromTry().
   - **Throwable**: Enhanced error type

8. **IO<R,E,A>**: Lazy, composable effect type with typed errors and dependency injection.
   - **R** = Requirements (environment/dependencies needed to run)
   - **E** = Error type (typed failures)
   - **A** = Success type (value produced on success)
   - Key features:
     - Lazy execution (nothing runs until explicitly executed)
     - Unified sync/async API (auto-detects Promise returns)
     - Typed errors at compile time
     - Composable via map/flatMap
     - Dependency injection via Tag/Layer/Context
     - Structured concurrency: bracket, race, timeout
     - Generator do-notation (`IO.gen`) and builder do-notation (`IO.Do`)
     - Error handling: catchTag, catchAll, retry, retryWithDelay, retryWhile, retryWithBackoff
     - Value-driven repetition: repeatUntil, repeatWhile, IO.iterate (bounded by RepeatExhausted)
     - Execution methods: run(), runOrThrow(), runSync(), runSyncOrThrow(), runExit(), runOption(), runTry()
     - Outcomes: `Exit<E, A>` = Success | Failure | Die | Interrupted, returned by runExit().
       `Failure` carries a value from the declared `E` channel; `Die` carries a **defect** —
       a value that is not an `E` (a throwing `IO.sync` thunk, a throwing map/flatMap/mapError
       callback, or `IO.die`). `run()` returns `Either`, which has no branch for either a defect
       or an interruption, so both arrive in the `Left`; `runExit()` is what keeps them apart.
       Defects stay recoverable — recover/recoverWith/fold/mapError treat `Die` as `Failure`.
       `fold`'s `onDie` and `match`'s `Die` are optional and fall back to the failure handler.
   - Testing utilities:
     - **TestClock**: Controlled time for testing timeouts/delays
     - **TestContext**: Test environment with mocked services
