MultiFocus

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

Attributes

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

Members list

Grouped members

Instances

export affine2multifocus: [F[_] : Alternative : Foldable]
Exported from MultiFocusK

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
export either2multifocus: [F[_] : Alternative : Foldable]
Exported from MultiFocusK

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
export forget2multifocus: [F[_]]
Exported from MultiFocusK

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
export forgetful2multifocus: [F[_] : Applicative : Foldable]
Exported from MultiFocusK

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
Exported from MultiFocusK

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 the RepresentativeIndex witness the bridge was built with.

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 the RepresentativeIndex witness the bridge was built with.

'''Constant-bundle contract.''' The witness read is sound only while the bundle it is handed is constant — true for direct use (modify / replace map a constant rebuild, so the read-at-at and the written value agree) and for mfAssocFunction1's broadcast branch, which routes a singleton bundle per position. It is NOT sound for an arbitrary varying bundle, which is why the product is a Function1BroadcastOptic: the kernel recognises it and composes the write per index (broadcastFrom) rather than passing a per-position bundle through from. The read side needs no such hook — to already broadcasts the single focus, so the kernel just reads the bundle at the index it wants. See the fixedtraversal-fold spike doc.

The using clause is the cost side of that contract: the index has to come from the caller's scope, because this Composer has none to give and a forged index is exactly what the witness removes. Index types with a canonical value (Int, Boolean, Unit, singletons) resolve import-free off RepresentativeIndex; anything else needs a local given or an explicit RepresentativeIndex.at. An uninhabited index type gets no instance — the bridge refuses rather than reading a bundle at a value that cannot exist.

Attributes

Source
MultiFocus.scala
export mfAssoc: [F[_] : Traverse : MultiFocusFromList, Xo, Xi]
Exported from MultiFocusK

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
export mfAssocFunction1: [X0, Xo, Xi]
Exported from MultiFocusK

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.

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 READ side needs no special case: it reads the inner's bundle at the index the outer's element came from (kC(i) = inner.to(kO(i))._2(i)), which a Function1BroadcastOptic answers with its broadcast focus and a bundle carrier with element i — so element i is read at i in both shapes rather than element 0's bundle being reused.

The WRITE side does need one, because the two shapes disagree about what a bundle means. A broadcast inner builds exactly ONE value, so it is written per index (kB(i) = inner.broadcastFrom(kD(i))); handing it the per-position bundle through from would sample one index and rebuild every position from that single value — the collapse grate ∘ iso used to have. A bundle inner's from is a bundle-level rebuild, so it consumes the whole write bundle once and the outer receives the constant rebuild of that single result.

See docs/research/2026-04-29-fixedtraversal-fold-spike.md.

Attributes

Source
MultiFocus.scala
export mfAssocPSVec: [Xo, Xi]
Exported from MultiFocusK

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
export mfFold: [F[_] : Foldable]
Exported from MultiFocusK

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
export mfFunctor: [F[_] : Functor]
Exported from MultiFocusK

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
export mfTraverse: [F[_] : Traverse]
Exported from MultiFocusK

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
export multifocus2forget: [F[_]]
Exported from MultiFocusK

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
export multifocus2modify: [F[_] : Functor]
Exported from MultiFocusK

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

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

Attributes

Source
MultiFocus.scala
export tuple2multifocus: [F[_] : Applicative : Foldable]
Exported from MultiFocusK

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

Constructors

def apply[F[_], A]: Optic[F[A], F[A], A, A, MultiFocus[F]]
Exported from MultiFocusK

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]]
Exported from MultiFocusK

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 pApply[F[_], A, B]: Optic[F[A], F[B], A, B, MultiFocus[F]]
Exported from MultiFocusK

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 => _$41]]
Exported from MultiFocusK

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).

Position is a read-time argument, never a property of the optic: the index is supplied per call by the .at(i) extension (g.at(i)(fa) == F.index(fa)(i)), and Representable has no canonical Representation to hand a constructor anyway — Function1[Boolean, *] has no privileged Boolean, and Function1[Nothing, *] has no index at all. So this factory takes no representative index, and the built optic carries none: X = Unit, and the whole index-parametric read lives in the focus bundle. (Pre-0.19 a second name, representableAt(F)(repr0), took exactly such an index; it built this same optic — see the changelog for the removal.) The one reader that cannot take its index per call — the inbound Iso bridge's own from, which is handed the whole bundle by the kernel and has no caller to ask — is given a RepresentativeIndex at construction instead (see that type's doc).

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 => _$45]]
Exported from MultiFocusK

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

Value members

Concrete methods

transparent inline def apply[F[_], X, A](x: X, fa: F[A]): MultiFocusK[F, X, A]

Pair a leftover x with a focus vector fa as the carrier value. Identity at runtime (the opaque type erases to the pair); the unwrap boundary is MultiFocusK.context / MultiFocusK.foci.

Pair a leftover x with a focus vector fa as the carrier value. Identity at runtime (the opaque type erases to the pair); the unwrap boundary is MultiFocusK.context / MultiFocusK.foci.

Attributes

Source
MultiFocus.scala

Exports

Defined exports

final type AssocSndZ = AssocSndZ
Exported from MultiFocusK$

Attributes

Source
MultiFocus.scala
Exported from MultiFocusK

Attributes

Source
MultiFocus.scala
Exported from MultiFocusK

Attributes

Source
MultiFocus.scala
Exported from MultiFocusK

Attributes

Source
MultiFocus.scala