IronPrism

dev.constructive.eo.iron.IronPrism
object IronPrism

Prisms for Iron refinements.

A refinement checked at runtime is a partial conversion A ⇀ A :| C with a total way back, and that is exactly a Prism: getOption tests the constraint (hit = the refined value, miss = the untouched source), reverseGet forgets it. Both Prism laws hold for any pure constraint — a value that passed the test passes it again, and forgetting a refinement gives back the very value that was refined.

Each constructor needs only Iron's RuntimeConstraint, which Iron derives from any compile-time Constraint at a call site where the types are concrete, so every built-in and user-defined constraint qualifies. Refinements Iron proves at compile time (refine on a literal) need no optic: they cannot miss.

 import io.github.iltotore.iron.constraint.numeric.Positive

 val positive = IronPrism[Int, Positive]
 positive.getOption(42)                        // Some(42: Int :| Positive)
 positive.getOption(-1)                        // None

 // Lens ∘ Prism = Optional: only valid ages get written.
 val age = Lens[Person, Int](_.age, (p, a) => p.copy(age = a)).andThen(positive)

 // Traversal ∘ Prism = filtering Traversal: only the positive elements are visited.
 Traversal.each[List, Int].andThen(positive).foldMap(List(_))(List(3, -1, 4))  // List(3, 4)

The constructors return the stock optics.MendTearPrism, so every fused composition and capability mixin of the core Prism applies unchanged. Like every Prism, a miss is a silent pass-through on write; when the reason matters, Iron's own refineEither carries the constraint's message. The .prism extension (import dev.constructive.eo.iron.prism) builds the same Prism from a RuntimeConstraint or Constraint instance.

Attributes

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

Members list

Grouped members

Constructors

def all[F[_], A, C](using F: Foldable[F], rtc: RuntimeConstraint[A, C]): MendTearPrism[F[A], F[A], F[IronType[A, C]], F[IronType[A, C]]]

All-or-nothing Prism F[A] ⇀ F[A :| C]: hits only when EVERY element satisfies C, and then refines the container as it stands — no copy, no per-element allocation (A :| C is an opaque alias of A). For the elements that do satisfy C out of a mixed container, compose instead: Traversal.each[F, A].andThen(IronPrism[A, C]).

All-or-nothing Prism F[A] ⇀ F[A :| C]: hits only when EVERY element satisfies C, and then refines the container as it stands — no copy, no per-element allocation (A :| C is an opaque alias of A). For the elements that do satisfy C out of a mixed container, compose instead: Traversal.each[F, A].andThen(IronPrism[A, C]).

Attributes

Source
IronPrism.scala
def apply[A, C](using rtc: RuntimeConstraint[A, C]): MendTearPrism[A, A, IronType[A, C], IronType[A, C]]

The Prism A ⇀ A :| C for a runtime-checked constraint C.

The Prism A ⇀ A :| C for a runtime-checked constraint C.

Attributes

Source
IronPrism.scala
def refined[T](using m: Mirror[T]): MendTearPrism[m.BaseType, m.BaseType, T, T]

The Prism BaseType ⇀ T for an Iron RefinedType / RefinedSubtype newtype T — given object Age extends RefinedType[Int, Positive]; type Age = Age.T, IronPrism.refined[Age] focuses the Ints that are valid ages. From the companion itself, Age.prism is the same.

The Prism BaseType ⇀ T for an Iron RefinedType / RefinedSubtype newtype T — given object Age extends RefinedType[Int, Positive]; type Age = Age.T, IronPrism.refined[Age] focuses the Ints that are valid ages. From the companion itself, Age.prism is the same.

Attributes

Source
IronPrism.scala