dev.constructive.eo.data

Carriers — the F[_, _] shapes an optics.Optic's to / from run through: Direct (plain focus, no leftover), Either (prism miss), Affine (miss '''or''' hit-with-context), Forget / opaque ForgetK (read-only collapse), ModifyF (effectful write), MultiFocus / opaque MultiFocusK (many foci), plus the perf substrate (PSVec and the array builders). Each carrier's companion hosts its typeclass instances, so composition resolves with no imports.

Attributes

Members list

Type members

Classlikes

sealed trait Affine[A, B]

Carrier for the Optional family — sealed hierarchy: Affine.Miss (no focus; carries Fst[A]) and Affine.Hit (focus present; carries Snd[A] + B). Miss / Hit store fields directly (no Either / Tuple2 wrapper); a .affine: Either[Fst[A], (Snd[A], B)] legacy accessor reconstructs the old view on demand. Prefer matching Miss(...) / Hit(...) for zero-alloc access.

Carrier for the Optional family — sealed hierarchy: Affine.Miss (no focus; carries Fst[A]) and Affine.Hit (focus present; carries Snd[A] + B). Miss / Hit store fields directly (no Either / Tuple2 wrapper); a .affine: Either[Fst[A], (Snd[A], B)] legacy accessor reconstructs the old view on demand. Prefer matching Miss(...) / Hit(...) for zero-alloc access.

At every constructor site A is a concrete Tuple2 (so Fst[A] / Snd[A] reduce); when carried through an Optic[…, Affine] existential, A is abstract and the match types stay inert.

Type parameters

A

existential leftover tuple

B

focus type

Attributes

Companion
object
Source
Affine.scala
Supertypes
class Object
trait Matchable
class Any
Known subtypes
class Hit[A, B]
class Miss[A, B]
object Affine

Constructors and typeclass instances for Affine.

Constructors and typeclass instances for Affine.

Attributes

Companion
trait
Source
Affine.scala
Supertypes
class Object
trait Matchable
class Any
Self type
Affine.type
object Direct

Typeclass instances for Direct, plus the wrap / unwrap boundary. Every operation collapses to plain function application at runtime — zero per-call overhead beyond the user's function.

Typeclass instances for Direct, plus the wrap / unwrap boundary. Every operation collapses to plain function application at runtime — zero per-call overhead beyond the user's function.

Attributes

Source
Direct.scala
Supertypes
class Object
trait Matchable
class Any
Self type
Direct.type
object Forget

API façade under the carrier's public name. The instances live in ForgetK (the opaque anchor's companion, where implicit scope finds them); this re-export keeps Forget.assocFor call-shapes and legacy import data.Forget.given working.

API façade under the carrier's public name. The instances live in ForgetK (the opaque anchor's companion, where implicit scope finds them); this re-export keeps Forget.assocFor call-shapes and legacy import data.Forget.given working.

Attributes

Source
Forget.scala
Supertypes
class Object
trait Matchable
class Any
Self type
Forget.type

Capability ladder for Forget. Each typeclass on F unlocks a matching optic operation:

Capability ladder for Forget. Each typeclass on F unlocks a matching optic operation:

 F: Functor      →  ForgetfulFunctor[Forget[F]]              →  .modify / .replace
 F: Foldable     →  ForgetfulFold[Forget[F]]                 →  .foldMap
 F: Traverse     →  ForgetfulTraverse[Forget[F], Applicative] →  .modifyA, .all
 F: Applicative  →  ForgetfulApplicative[Forget[F]]          →  .put
 F: Monad        →  AssociativeFunctor[Forget[F], _, _]      →  same-carrier .andThen
                                                                (algebraic-lens shape)

Forget[F]'s X is phantom — Traversal / Fold need no outer-structural context on from. For cases where the outer's leftover must survive, use the pair carrier MultiFocus; Forget[F] injects trivially into it via Composer[Forget[F], MultiFocus[F]]. Direct-targeting instances live in Direct.

Attributes

Source
Forget.scala
Supertypes
class Object
trait Matchable
class Any
Self type
ForgetK.type

Lower-priority instance drawer — holds the FlatMap + Comonad AssociativeFunctor which composes via coflatMap (parallel-fold semantics, genuinely different from the Monad-based algebraic-lens composition in ForgetK). Kept at lower priority so Monad wins when both apply.

Lower-priority instance drawer — holds the FlatMap + Comonad AssociativeFunctor which composes via coflatMap (parallel-fold semantics, genuinely different from the Monad-based algebraic-lens composition in ForgetK). Kept at lower priority so Monad wins when both apply.

Attributes

Source
Forget.scala
Supertypes
class Object
trait Matchable
class Any
Known subtypes
object ForgetK
object ModifyF

Typeclass instances for ModifyF.

Typeclass instances for ModifyF.

Attributes

Companion
class
Source
ModifyF.scala
Supertypes
class Object
trait Matchable
class Any
Self type
ModifyF.type
final class ModifyF[A, B](val modifier: (Fst[A], Snd[A] => B)) extends AnyVal

Carrier for the Modify family — pairs a source Fst[A] with a continuation Snd[A] => B.

Carrier for the Modify family — pairs a source Fst[A] with a continuation Snd[A] => B.

Same-carrier composition (modify.andThen(modify)) ships via ModifyF.assocModifyFAssociativeFunctor[ModifyF, Xo, Xi] with type Z = (Fst[Xo], Snd[Xi]). The deferred-modify semantic fits the protocol once you observe that composeTo only needs to seed (xo, identity) (no inner-to call required, since ModifyF's continuation is structurally identity at every canonical construction site — coerceToModify and Modify.apply); composeFrom then extracts the user's c2d from the mapped continuation and routes it through inner.from then outer.from. The asInstanceOf casts inside the instance are sound under the universal convention that every ModifyF optic stores X = (S_outer, A_focus) (enforced at every construction site).

Type parameters

A

existential leftover tuple

B

focus written back

Attributes

Companion
object
Source
ModifyF.scala
Supertypes
class AnyVal
trait Matchable
class Any
object MultiFocus

API façade under the carrier's public name. The instances live in MultiFocusK (the opaque anchor's companion, where implicit scope finds them); this re-export keeps MultiFocus.apply / MultiFocus.fromLensF call-shapes and legacy import data.MultiFocus.given working.

API façade under the carrier's public name. The instances live in MultiFocusK (the opaque anchor's companion, where implicit scope finds them); this re-export keeps MultiFocus.apply / MultiFocus.fromLensF call-shapes and legacy import data.MultiFocus.given working.

Attributes

Source
MultiFocus.scala
Supertypes
class Object
trait Matchable
class Any
Self type
MultiFocus.type
object MultiFocusK

Instance home for MultiFocusK — the capability instances (mfFunctor / mfFold / mfTraverse), the same-carrier composition kernels (mfAssoc and its Function1 / PSVec specialisations), the Composer bridges from every other carrier, the factories, and the .collect* / .at aggregation surface. Being the opaque anchor's companion, everything here is in implicit scope with no import; the public call-shape is the MultiFocus façade.

Instance home for MultiFocusK — the capability instances (mfFunctor / mfFold / mfTraverse), the same-carrier composition kernels (mfAssoc and its Function1 / PSVec specialisations), the Composer bridges from every other carrier, the factories, and the .collect* / .at aggregation surface. Being the opaque anchor's companion, everything here is in implicit scope with no import; the public call-shape is the MultiFocus façade.

Attributes

Source
MultiFocus.scala
Supertypes
class Object
trait Matchable
class Any
Self type
object PSVec

Constructors for PSVec — the primary entry points are empty, singleton, and unsafeWrap (zero-copy from an Array[AnyRef]). The three Slice / Single / Empty subclasses are internal to the dev.constructive.eo.data package and stable across release lines only at the aggregate PSVec supertype level.

Constructors for PSVec — the primary entry points are empty, singleton, and unsafeWrap (zero-copy from an Array[AnyRef]). The three Slice / Single / Empty subclasses are internal to the dev.constructive.eo.data package and stable across release lines only at the aggregate PSVec supertype level.

Attributes

Companion
trait
Source
PSVec.scala
Supertypes
class Object
trait Matchable
class Any
Self type
PSVec.type
sealed trait PSVec[+B]

Lightweight array-backed focus vector underlying MultiFocus[PSVec]. Three variants so empty and singleton focus vectors don't pay a backing-array allocation:

Lightweight array-backed focus vector underlying MultiFocus[PSVec]. Three variants so empty and singleton focus vectors don't pay a backing-array allocation:

  • PSVec.Empty — shared singleton; Prism / Affine miss branches allocate nothing.
  • PSVec.Single — element stored inline (~16 B vs a backing-array view's ~40 B).
  • PSVec.Slice — arbitrary (arr, offset, length) view. slice is a zero-copy pointer update — what mfAssocPSVec.composeFrom relies on for O(1) per-element reassembly.

Equality is value-based across variants.

Attributes

Companion
object
Source
PSVec.scala
Supertypes
class Object
trait Matchable
class Any
Known subtypes
object Empty
class Single[B]
class Slice[B]

Types

opaque type Direct[X, A]

Identity carrier: Direct[X, A] = A (opaque). X is phantom. Used by Iso and Getter where the focus is fully determined and no reassembly information is needed — the optic's to / from are plain functions, so it is the forgetful functor (it forgets the leftover X entirely). Its instances therefore live under the Forgetful* typeclasses (forgetful.ForgetfulFunctor, forgetful.ForgetfulTraverse, …). The F-shape sibling Forget lives in its own file.

Identity carrier: Direct[X, A] = A (opaque). X is phantom. Used by Iso and Getter where the focus is fully determined and no reassembly information is needed — the optic's to / from are plain functions, so it is the forgetful functor (it forgets the leftover X entirely). Its instances therefore live under the Forgetful* typeclasses (forgetful.ForgetfulFunctor, forgetful.ForgetfulTraverse, …). The F-shape sibling Forget lives in its own file.

opaque (not a transparent alias) so it is a distinct type for implicit search: object Direct is its companion, so Accessor[Direct], AssociativeFunctor[Direct, …], etc. resolve via companion scope with no import, and the compiler never dealiases Direct[X, A] to A (which would lose those givens). It still erases to A, so Direct.apply (wrap) / value (unwrap) are identity at runtime.

Attributes

Source
Direct.scala
type Forget[F[_]] = [X, A] =>> ForgetK[F, X, A]

Curried carrier view of ForgetK — the F[_, _] shape Optic expects.

Curried carrier view of ForgetK — the F[_, _] shape Optic expects.

Attributes

Source
Forget.scala
opaque type ForgetK[F[_], X, A]

Adapt a F[_] container to the two-parameter carrier shape by wrapping it under the phantom X. Equivalent to the classic Haskell newtype Forget r a b = Forget (a -> r) construction but applied to a type constructor F: Forget[F][X, A] = F[A], ignoring X completely.

Adapt a F[_] container to the two-parameter carrier shape by wrapping it under the phantom X. Equivalent to the classic Haskell newtype Forget r a b = Forget (a -> r) construction but applied to a type constructor F: Forget[F][X, A] = F[A], ignoring X completely.

Used by dev.constructive.eo.optics.Fold (read-only), its build-only dual dev.constructive.eo.optics.Unfold, and the multi-focus family (dev.constructive.eo.data.MultiFocus) as a uniform "F-shape carrier" whose optic-level capabilities scale with the typeclasses F itself admits.

Attributes

Source
Forget.scala
type Fst[T] = T match { case (f, s) => f }

Extract the first element type of a Tuple2. Stays as an unreduced match type when T is not a Tuple2 — this is load bearing for Affine.assoc accepting unbounded existentials.

Extract the first element type of a Tuple2. Stays as an unreduced match type when T is not a Tuple2 — this is load bearing for Affine.assoc accepting unbounded existentials.

Attributes

Source
Affine.scala
type MultiFocus[F[_]] = [X, A] =>> MultiFocusK[F, X, A]

Curried carrier view of MultiFocusK — the F[_, _] shape Optic expects.

Curried carrier view of MultiFocusK — the F[_, _] shape Optic expects.

Attributes

Source
MultiFocus.scala
opaque type MultiFocusK[F[_], X, A]

Unified pair carrier for the algebraic-lens, kaleidoscope, and grate optic families — MultiFocus[F][X, A] = (X, F[A]): a structural leftover X paired with a focus collection / aggregate / rebuild-closure F[A]. One carrier serves all three families; only the choice of F differs (a container for Traversal, Function1-shaped for the grate encoding, …).

Unified pair carrier for the algebraic-lens, kaleidoscope, and grate optic families — MultiFocus[F][X, A] = (X, F[A]): a structural leftover X paired with a focus collection / aggregate / rebuild-closure F[A]. One carrier serves all three families; only the choice of F differs (a container for Traversal, Function1-shaped for the grate encoding, …).

The kaleidoscope aggregation ("summarise the foci, write the summary back") has two natural derivations, and the choice is structural — not derivable from a single typeclass:

  • Functor-broadcast: fa.map(_ => f(fa)). Length-preserving; default. Needs Functor[F].
  • Applicative-broadcast: F.pure(f(fa)). Singleton/cartesian. Needs Applicative[F].

The default is the first; List users wanting the singleton collapse can compose _.headOption downstream or call collectList explicitly. See docs/research/2026-04-29-fixedtraversal-fold-spike.md for the grate-absorption justification.

Type parameters

F

classifier shape — operation requirements:

  • .modify / .replace need Functor[F].
  • .foldMap needs Foldable[F].
  • .modifyA / .all need Traverse[F].
  • .collectMap / .collectWith need Functor[F]; collectList is List-specific.
  • Same-carrier .andThen needs Traverse[F] + MultiFocusFromList[F].
  • fromPrismF / fromOptionalF need MonoidK[F].

Attributes

Source
MultiFocus.scala
type Snd[T] = T match { case (f, s) => s }

Extract the second element type of a Tuple2. See Fst.

Extract the second element type of a Tuple2. See Fst.

Attributes

Source
Affine.scala