Plated

dev.constructive.eo.optics.Plated
See thePlated companion object
trait Plated[S]

A self-similar structure: a value of S whose immediate sub-terms are themselves S. The single member plate is a Traversal[S, S] focusing those immediate children — the cats-eo analogue of Haskell lens's Plated class (plate :: Traversal' a a).

The recursion combinators in the companion (Plated.transform, Plated.rewrite, Plated.children, Plated.universe) build on plate to walk the whole tree. They are stack-safe on deep trees: transform recurses on the call stack while shallow and falls back to a heap-stack machine past a depth bound, rewrite trampolines through cats.Eval, and universe / children use an explicit worklist — a degenerate 100k-deep tree is fine.

The children are carried as a PSVec (the MultiFocus[PSVec] carrier's focus vector), so the read path and the write path share one representation with no List round-trips — see childrenVec.

Get an instance by hand via Plated.fromChildren / Plated.fromChildrenVec, by deriving one with dev.constructive.eo.generics.plate[S], or — when you have already built the self-traversal as an optic — by calling .asPlated on it (see the extension methods below).

Attributes

See also

Traversal.selfChildren for the underlying carrier.

Companion
object
Source
Plated.scala
Graph
Supertypes
class Object
trait Matchable
class Any

Members list

Value members

Abstract methods

def plate: Optic[S, S, S, S, MultiFocus[PSVec]]

The immediate-children self-traversal.

The immediate-children self-traversal.

Attributes

Source
Plated.scala

Concrete methods

def childrenArray(s: S): Array[AnyRef]

The immediate children as a fresh Array[AnyRef] the caller may mutate in place. The default copies (childrenVec(s).toAnyRefArray) so it is safe for any instance; Plated.fromChildrenVec overrides it to hand back the freshly-built backing array copy-free. The recursion-scheme cata engine folds each child's result into this array in place, reusing the one array instead of allocating a separate result accumulator per node.

The immediate children as a fresh Array[AnyRef] the caller may mutate in place. The default copies (childrenVec(s).toAnyRefArray) so it is safe for any instance; Plated.fromChildrenVec overrides it to hand back the freshly-built backing array copy-free. The recursion-scheme cata engine folds each child's result into this array in place, reusing the one array instead of allocating a separate result accumulator per node.

Attributes

Source
Plated.scala
def childrenVec(s: S): PSVec[S]

Immediate children as a PSVec — the representation both the read path (Plated.children / Plated.universe) and the write path (Plated.transform / Plated.rewrite, through the carrier) share. Defaults to reading the carrier directly (plate.to(s)._2); Plated.fromChildren / Plated.fromChildrenVec (hence every generics.plate[S]-derived instance) override it to return the children with no tuple allocation. Either way nothing is converted to a List and back — that round-trip was the read/write hot-path tax.

Immediate children as a PSVec — the representation both the read path (Plated.children / Plated.universe) and the write path (Plated.transform / Plated.rewrite, through the carrier) share. Defaults to reading the carrier directly (plate.to(s)._2); Plated.fromChildren / Plated.fromChildrenVec (hence every generics.plate[S]-derived instance) override it to return the children with no tuple allocation. Either way nothing is converted to a List and back — that round-trip was the read/write hot-path tax.

Attributes

Source
Plated.scala
def rebuild(parent: S, children: PSVec[S]): S

Reassemble parent with children swapped in (same arity / order) — the write-path counterpart to childrenVec. Defaults to threading the carrier; Plated.fromChildren / Plated.fromChildrenVec (hence every generics.plate[S]-derived instance) override it with the raw rebuild function so Plated.transform rebuilds without allocating the carrier's (x, PSVec) tuple per node. On the default (.asPlated) path this and childrenVec each call plate.to, so a transform over a hand-built optic pays two to calls per internal node — derived / fromChildrenVec instances override both and pay none.

Reassemble parent with children swapped in (same arity / order) — the write-path counterpart to childrenVec. Defaults to threading the carrier; Plated.fromChildren / Plated.fromChildrenVec (hence every generics.plate[S]-derived instance) override it with the raw rebuild function so Plated.transform rebuilds without allocating the carrier's (x, PSVec) tuple per node. On the default (.asPlated) path this and childrenVec each call plate.to, so a transform over a hand-built optic pays two to calls per internal node — derived / fromChildrenVec instances override both and pay none.

Attributes

Source
Plated.scala