MultiFocusK

dev.constructive.eo.data.MultiFocus$package.MultiFocusK
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.

Attributes

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

Members list

Grouped members

Instances

Optional → MultiFocus[F] — mirror of either2multifocus over the Affine miss / hit split.

Optional → MultiFocus[F] — mirror of either2multifocus over the Affine miss / hit split.

Attributes

Source
MultiFocus.scala

Optional → MultiFocus[PSVec]. Mixes in MultiFocusPSMaybeHit so mfAssocPSVec skips the per-element Affine[o.X, Unit] wrapper the generic path would build.

Optional → MultiFocus[PSVec]. Mixes in MultiFocusPSMaybeHit so mfAssocPSVec skips the per-element Affine[o.X, Unit] wrapper the generic path would build.

Attributes

Source
MultiFocus.scala

Optional → MultiFocus[PSVec]. Mixes in MultiFocusPSMaybeHit so mfAssocPSVec skips the per-element Affine[o.X, Unit] wrapper the generic path would build.

Optional → MultiFocus[PSVec]. Mixes in MultiFocusPSMaybeHit so mfAssocPSVec skips the per-element Affine[o.X, Unit] wrapper the generic path would build.

Attributes

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

Prism → MultiFocus[F] — hit becomes a pure singleton, miss becomes Alternative[F].empty.

Prism → MultiFocus[F] — hit becomes a pure singleton, miss becomes Alternative[F].empty.

Attributes

Source
MultiFocus.scala

Prism → MultiFocus[PSVec] — lifts a Prism-carrier optic so prism.andThen(traversal) type-checks. Mixes in MultiFocusPSMaybeHit so the PSVec-specialised mfAssocPSVec body skips the per-element Either[o.X, Unit] wrapper the generic to path would build.

Prism → MultiFocus[PSVec] — lifts a Prism-carrier optic so prism.andThen(traversal) type-checks. Mixes in MultiFocusPSMaybeHit so the PSVec-specialised mfAssocPSVec body skips the per-element Either[o.X, Unit] wrapper the generic to path would build.

Attributes

Source
MultiFocus.scala
object either2multifocusPSVec extends Composer[Either, MultiFocus[PSVec]]

Prism → MultiFocus[PSVec] — lifts a Prism-carrier optic so prism.andThen(traversal) type-checks. Mixes in MultiFocusPSMaybeHit so the PSVec-specialised mfAssocPSVec body skips the per-element Either[o.X, Unit] wrapper the generic to path would build.

Prism → MultiFocus[PSVec] — lifts a Prism-carrier optic so prism.andThen(traversal) type-checks. Mixes in MultiFocusPSMaybeHit so the PSVec-specialised mfAssocPSVec body skips the per-element Either[o.X, Unit] wrapper the generic to path would build.

Attributes

Source
MultiFocus.scala
Supertypes
trait Composer[Either, MultiFocus[PSVec]]
class Object
trait Matchable
class Any
Self type

Forget[F] ↪ MultiFocus[F] — a Fold slots into the pair carrier with X = Unit.

Forget[F] ↪ MultiFocus[F] — a Fold slots into the pair carrier with X = Unit.

Attributes

Source
MultiFocus.scala

Iso → MultiFocus[F]. Requires Applicative[F] to broadcast the Iso's plain A focus into a singleton F[A]; the write-back picks the singleton out (throws on cardinality ≠ 1).

Iso → MultiFocus[F]. Requires Applicative[F] to broadcast the Iso's plain A focus into a singleton F[A]; the write-back picks the singleton out (throws on cardinality ≠ 1).

Attributes

Source
MultiFocus.scala

Iso ↪ MultiFocus[Function1[X0, *]] — the Iso side of the grate-shaped surface. Iso's forward to: S => A is broadcast to the constant rebuild _ => a; the reverse reads the rebuild at any X0 (null sentinel — sound because no shipped rebuild observes its argument; see the fixedtraversal-fold spike doc).

Iso ↪ MultiFocus[Function1[X0, *]] — the Iso side of the grate-shaped surface. Iso's forward to: S => A is broadcast to the constant rebuild _ => a; the reverse reads the rebuild at any X0 (null sentinel — sound because no shipped rebuild observes its argument; see the fixedtraversal-fold spike doc).

Attributes

Source
MultiFocus.scala
given mfAssoc: [F[_] : Traverse : MultiFocusFromList, Xo, Xi] => mfAssoc[F, Xo, Xi]

Same-carrier composition for MultiFocus[F]traversal.andThen(traversal), F-parametric. Z = (Xo, F[(Xi, Int)]): the outer leftover plus, per outer focus, the inner leftover and its focus count, so composeFrom can carve the flat modified vector back into per-element slices (cursor over an array snapshot). Inners that mix in MultiFocusSingleton (the Lens bridge) take an always-hit fast path that skips the per-element inner fold. Flat focus order is the outer's traversal order, inner order within each element.

Same-carrier composition for MultiFocus[F]traversal.andThen(traversal), F-parametric. Z = (Xo, F[(Xi, Int)]): the outer leftover plus, per outer focus, the inner leftover and its focus count, so composeFrom can carve the flat modified vector back into per-element slices (cursor over an array snapshot). Inners that mix in MultiFocusSingleton (the Lens bridge) take an always-hit fast path that skips the per-element inner fold. Flat focus order is the outer's traversal order, inner order within each element.

Attributes

Source
MultiFocus.scala

Function1-shaped same-carrier composition — the grate-absorbed case. The general mfAssoc requires Traverse[F] + MultiFocusFromList[F]; Function1[X0, *] admits neither, so this instance composes the rebuild closures directly. The outer rebuild is a constant broadcast — sound because every shipped outer (iso-morphed, tuple-built) rebuilds via broadcast anyway. See docs/research/2026-04-29-fixedtraversal-fold-spike.md.

Function1-shaped same-carrier composition — the grate-absorbed case. The general mfAssoc requires Traverse[F] + MultiFocusFromList[F]; Function1[X0, *] admits neither, so this instance composes the rebuild closures directly. The outer rebuild is a constant broadcast — sound because every shipped outer (iso-morphed, tuple-built) rebuilds via broadcast anyway. See docs/research/2026-04-29-fixedtraversal-fold-spike.md.

Attributes

Source
MultiFocus.scala
given mfAssocPSVec: [Xo, Xi] => mfAssocPSVec[Xo, Xi]

PSVec-specialised same-carrier composition. Where the generic mfAssoc body builds two intermediate List accumulators + materialises via fromList, this body writes directly into IntArrBuilder / ObjArrBuilder and stores the existential as parallel arrays in AssocSndZ, sidestepping the per-element (Xi, Int) Tuple2 the generic path pays. Fast paths for MultiFocusSingleton (always-hit, Lens bridge) and MultiFocusPSMaybeHit (Prism / Optional bridges) inners; reassembly hands each inner an O(1) PSVec.slice view. See docs/research/2026-04-29-powerseries-fold-spike.md.

PSVec-specialised same-carrier composition. Where the generic mfAssoc body builds two intermediate List accumulators + materialises via fromList, this body writes directly into IntArrBuilder / ObjArrBuilder and stores the existential as parallel arrays in AssocSndZ, sidestepping the per-element (Xi, Int) Tuple2 the generic path pays. Fast paths for MultiFocusSingleton (always-hit, Lens bridge) and MultiFocusPSMaybeHit (Prism / Optional bridges) inners; reassembly hands each inner an O(1) PSVec.slice view. See docs/research/2026-04-29-powerseries-fold-spike.md.

Attributes

Source
MultiFocus.scala
given mfFold: [F[_] : Foldable] => mfFold[F]

ForgetfulFold[MultiFocus[F]] via Foldable[F] — folds the focus vector, discarding the leftover. Unlocks .foldMap / .headOption / .length / .exists.

ForgetfulFold[MultiFocus[F]] via Foldable[F] — folds the focus vector, discarding the leftover. Unlocks .foldMap / .headOption / .length / .exists.

Attributes

Source
MultiFocus.scala
given mfFunctor: [F[_] : Functor] => mfFunctor[F]

ForgetfulFunctor[MultiFocus[F]] via Functor[F] — maps every focus, leftover untouched. Unlocks .modify / .replace on Traversal-family optics.

ForgetfulFunctor[MultiFocus[F]] via Functor[F] — maps every focus, leftover untouched. Unlocks .modify / .replace on Traversal-family optics.

Attributes

Source
MultiFocus.scala
given mfTraverse: [F[_] : Traverse] => mfTraverse[F]

ForgetfulTraverse[MultiFocus[F], Applicative] via Traverse[F] — effectful rewrite of every focus in F's traversal order. Unlocks .modifyA / .all.

ForgetfulTraverse[MultiFocus[F], Applicative] via Traverse[F] — effectful rewrite of every focus in F's traversal order. Unlocks .modifyA / .all.

Attributes

Source
MultiFocus.scala

MultiFocus[F] ↪ Forget[F] — read-only escape: discard the structural leftover, keep the focused F[A]. An explicit carrier morph alongside the carrier-wide Optic.foldMap / .headOption / .length / .exists extension methods.

MultiFocus[F] ↪ Forget[F] — read-only escape: discard the structural leftover, keep the focused F[A]. An explicit carrier morph alongside the carrier-wide Optic.foldMap / .headOption / .length / .exists extension methods.

Structurally this is the inverse of forget2multifocus — both Composer directions ship. That's normally banned by the cats-eo Morph resolution invariant (a bidirectional pair makes Morph[Forget[F], MultiFocus[F]] ambiguous because both leftToRight and rightToLeft fire). The Composer ships anyway because:

  1. The from side requires T = Unit (Forget loses the leftover, so it can't reconstruct a T ≠ Unit). Only T-Unit MultiFocus optics qualify, which the type system enforces at use sites.
  2. Any chain-resolution ambiguity surfaces at forget.andThen(multifocus) / multifocus.andThen(fold) call sites — the user resolves by routing through the explicit Composer[..].to(o) form rather than .andThen.

Practical Morph fallout: if a user actually hits the ambiguity, they get a clear implicit-not- found message naming both Composers; the workaround is one extra .morph-shaped call.

Attributes

Source
MultiFocus.scala

MultiFocus[F] → ModifyF. Uniform Modify widening for any Functor[F].

MultiFocus[F] → ModifyF. Uniform Modify widening for any Functor[F].

Attributes

Source
MultiFocus.scala

Lens → MultiFocus[F]. Mixes in MultiFocusSingleton so the mfAssoc fast-path fires.

Lens → MultiFocus[F]. Mixes in MultiFocusSingleton so the mfAssoc fast-path fires.

Attributes

Source
MultiFocus.scala

Lens → MultiFocus[PSVec]. GetReplaceLens fast-path elides the (s, get(s)) Tuple2 the generic body would build. The to body builds anonymous Optic values inline so MultiFocusSingleton can refer to o.X without tripping Scala 3's "class parent cannot refer to constructor parameters" rule.

Lens → MultiFocus[PSVec]. GetReplaceLens fast-path elides the (s, get(s)) Tuple2 the generic body would build. The to body builds anonymous Optic values inline so MultiFocusSingleton can refer to o.X without tripping Scala 3's "class parent cannot refer to constructor parameters" rule.

Attributes

Source
MultiFocus.scala
object tuple2multifocusPSVec extends Composer[Tuple2, MultiFocus[PSVec]]

Lens → MultiFocus[PSVec]. GetReplaceLens fast-path elides the (s, get(s)) Tuple2 the generic body would build. The to body builds anonymous Optic values inline so MultiFocusSingleton can refer to o.X without tripping Scala 3's "class parent cannot refer to constructor parameters" rule.

Lens → MultiFocus[PSVec]. GetReplaceLens fast-path elides the (s, get(s)) Tuple2 the generic body would build. The to body builds anonymous Optic values inline so MultiFocusSingleton can refer to o.X without tripping Scala 3's "class parent cannot refer to constructor parameters" rule.

Attributes

Source
MultiFocus.scala
Supertypes
trait Composer[Tuple2, MultiFocus[PSVec]]
class Object
trait Matchable
class Any
Self type

Constructors

def apply[F[_], A]: Optic[F[A], F[A], A, A, MultiFocus[F]]

Generic factory: X = F[A], focus = fa, rebuild = identity.

Generic factory: X = F[A], focus = fa, rebuild = identity.

Attributes

Source
MultiFocus.scala
def fromLensF[F[_], S, T, A, B](lens: Optic[S, T, F[A], F[B], Tuple2]): Optic[S, T, A, B, MultiFocus[F]]

Reinterpret a Lens whose focus is already an F[A] as a MultiFocus optic over the elements — the container the Lens reads IS the focus vector; X and the rebuild pass straight through.

Reinterpret a Lens whose focus is already an F[A] as a MultiFocus optic over the elements — the container the Lens reads IS the focus vector; X and the rebuild pass straight through.

Attributes

Source
MultiFocus.scala
def fromOptionalF[F[_] : MonoidK, S, T, A, B](opt: Optic[S, T, F[A], F[B], Affine]): Optic[S, T, A, B, MultiFocus[F]]

Reinterpret an Optional whose focus is an F[A] as a MultiFocus optic over the elements — the mirror of fromPrismF over the Affine miss / hit split (miss recycled via widenB, both directions).

Reinterpret an Optional whose focus is an F[A] as a MultiFocus optic over the elements — the mirror of fromPrismF over the Affine miss / hit split (miss recycled via widenB, both directions).

Attributes

Source
MultiFocus.scala
def fromPrismF[F[_] : MonoidK, S, T, A, B](prism: Optic[S, T, F[A], F[B], Either]): Optic[S, T, A, B, MultiFocus[F]]

Reinterpret a Prism whose focus is an F[A] as a MultiFocus optic over the elements — the miss branch surfaces as MonoidK[F].empty (zero foci) and passes the leftover back through the prism's build path on write.

Reinterpret a Prism whose focus is an F[A] as a MultiFocus optic over the elements — the miss branch surfaces as MonoidK[F].empty (zero foci) and passes the leftover back through the prism's build path on write.

Attributes

Source
MultiFocus.scala
def pApply[F[_], A, B]: Optic[F[A], F[B], A, B, MultiFocus[F]]

Polymorphic counterpart to apply — allows focus type change (F[A] => F[B]), the Traversal.pEach analogue at the generic factory. Sound for the same reason: the rebuild is identity on the written-back F[B], so no B ever has to fit an A-shaped hole. This is what un-pins the collect flavours' element type — pApply[F, A, Row].collectWith(...) emits a different row type than it read.

Polymorphic counterpart to apply — allows focus type change (F[A] => F[B]), the Traversal.pEach analogue at the generic factory. Sound for the same reason: the rebuild is identity on the written-back F[B], so no B ever has to fit an A-shaped hole. This is what un-pins the collect flavours' element type — pApply[F, A, Row].collectWith(...) emits a different row type than it read.

Attributes

Source
MultiFocus.scala
def representable[F[_], A](using F: Representable[F]): Optic[F[A], F[A], A, A, MultiFocus[[_] =>> F.Representation => _$37]]

Generic Function1-shaped factory — any Representable[F] container yields a MultiFocus[Function1[F.Representation, *]]-carrier optic over F[A] with focus A. Encoding: X = Unit, rebuild = F.Representation => A. On to(fa) snapshot F.index(fa); on from((_, k)) materialise via F.tabulate(k). The .modify(f) round-trip is exactly F.map(fa)(f).

Generic Function1-shaped factory — any Representable[F] container yields a MultiFocus[Function1[F.Representation, *]]-carrier optic over F[A] with focus A. Encoding: X = Unit, rebuild = F.Representation => A. On to(fa) snapshot F.index(fa); on from((_, k)) materialise via F.tabulate(k). The .modify(f) round-trip is exactly F.map(fa)(f).

Attributes

Source
MultiFocus.scala
def representableAt[F[_], A](F: Representable[F])(repr0: F.Representation): Optic[F[A], F[A], A, A, MultiFocus[[_] =>> F.Representation => _$40]]

Representable-indexed variant with explicit representative index. The repr0 argument is unused at runtime (rebuild operates pointwise via F.tabulate); preserved for API parity and to leave the door open for a future .lead accessor.

Representable-indexed variant with explicit representative index. The repr0 argument is unused at runtime (rebuild operates pointwise via F.tabulate); preserved for API parity and to leave the door open for a future .lead accessor.

Attributes

Source
MultiFocus.scala
def tuple[T <: Tuple, A](using sz: ValueOf[Size[T]], ev: Union[T] <:< A): Optic[T, T, A, A, MultiFocus[[_] =>> Int => _$42]]

Polymorphic homogeneous-tuple Function1-shaped factory. to(t) = ((), i => t._i), from((_, k)) materialises via Tuple.fromArray(Array.tabulate(size)(i => k(i))).

Polymorphic homogeneous-tuple Function1-shaped factory. to(t) = ((), i => t._i), from((_, k)) materialises via Tuple.fromArray(Array.tabulate(size)(i => k(i))).

Attributes

Example
 val g3 = MultiFocus.tuple[(Int, Int, Int), Int]
 g3.modify(_ + 1)((1, 2, 3))   // (2, 3, 4)
 g3.replace(42)((1, 2, 3))     // (42, 42, 42)
Source
MultiFocus.scala

Extensions

Extensions

extension [S, T, A, B](o: Optic[S, T, A, B, MultiFocus[List]])
def collectList(agg: List[A] => B)(using ev: S =:= List[A], ev2: T =:= List[B]): S => T

Singleton / cartesian aggregation, List-specific — collapses the whole focus list to ONE aggregated element: the result list has length 1 regardless of the focus count. Shape-changing, which is exactly what no Functor-based combinator can express; the length-preserving alternatives are collectMap / collectWith.

Singleton / cartesian aggregation, List-specific — collapses the whole focus list to ONE aggregated element: the result list has length 1 regardless of the focus count. Shape-changing, which is exactly what no Functor-based combinator can express; the length-preserving alternatives are collectMap / collectWith.

Attributes

Source
MultiFocus.scala
extension [S, T, A, B, F[_]](o: Optic[S, T, A, B, MultiFocus[F]])(using F: Functor[F])
def collectMap[C](agg: F[A] => C)(using ev: C =:= B): S => T

Functor-broadcast aggregation — preserves F-shape via map(_ => agg(fa)); every focus position receives the aggregate. Works for any Functor[F]; for List this is the ZipList-style length-preserving aggregation (use collectList for the shape-collapsing List-singleton semantics). For the generic apply factory (X = F[A], rebuild = identity), .collectMap is s => s.map(_ => agg(s)) — semantically Functor.map over the source.

Functor-broadcast aggregation — preserves F-shape via map(_ => agg(fa)); every focus position receives the aggregate. Works for any Functor[F]; for List this is the ZipList-style length-preserving aggregation (use collectList for the shape-collapsing List-singleton semantics). For the generic apply factory (X = F[A], rebuild = identity), .collectMap is s => s.map(_ => agg(s)) — semantically Functor.map over the source.

Attributes

Source
MultiFocus.scala
def collectWith(agg: F[A] => A => B): S => T

The algebraic-lens universal for the map-shaped collects — agg sees the whole focus collection ONCE, returns the per-focus rewrite, and that rewrite is mapped back over every position: fa.map(a => agg(fa)(a)). The currying is load-bearing: compute the batch summary in agg(fa), and the returned A => B runs per position without recomputing it.

The algebraic-lens universal for the map-shaped collects — agg sees the whole focus collection ONCE, returns the per-focus rewrite, and that rewrite is mapped back over every position: fa.map(a => agg(fa)(a)). The currying is load-bearing: compute the batch summary in agg(fa), and the returned A => B runs per position without recomputing it.

Subsumes both map-shaped siblings — collectMap(agg) = collectWith(fa => _ => agg(fa)) (constant per-focus function) and modify(f) = collectWith(_ => f) (aggregate ignored); pinned as laws MF4 / MF5. The shape-collapsing collectList is NOT expressible here: it changes the focus count, which no Functor-based combinator can. Requires only Functor[F], like collectMap.

Attributes

Source
MultiFocus.scala
extension [S, T, A, B, F[_]](o: Optic[S, T, A, B, MultiFocus[F]])(using F: Representable[F])
def at(i: F.Representation): S => A

Read the focus at a representative position. Requires Representable[F]. For MultiFocus[Function1[X0, *]], this is index(fa)(i) = fa(i).

Read the focus at a representative position. Requires Representable[F]. For MultiFocus[Function1[X0, *]], this is index(fa)(i) = fa(i).

Attributes

Source
MultiFocus.scala
extension [F[_], X, A](self: MultiFocusK[F, X, A])
transparent inline def context: X

The structural leftover. Identity at runtime.

The structural leftover. Identity at runtime.

Attributes

Source
MultiFocus.scala
transparent inline def foci: F[A]

The focus vector. Identity at runtime.

The focus vector. Identity at runtime.

Attributes

Source
MultiFocus.scala