Class: Plumb::Intersection
- Inherits:
-
Object
- Object
- Plumb::Intersection
- Includes:
- Composable, Conjunction
- Defined in:
- lib/plumb/intersection.rb
Overview
THE LATTICE MEET — the greatest lower bound of two types. Built by #>>, #/,
#where and #check when neither side changes the value, and by #& when it
cannot narrow the operands into one node.
Both sides validate the SAME value and return it untouched, so unlike And this
is not a pipeline between two types — it IS a type, describing the values that
satisfy both. The longer the chain, the narrower. Each side is a composed partial
identity: a check A ⇀ A narrowing the semantic type without touching the value.
Instance Attribute Summary
Attributes included from Conjunction
#children, #input_type, #output_type
Instance Method Summary collapse
-
#accepted_type ⇒ Object
A refinement accepts the constraint it actually passes — the right side's resolved output — not its #input_type, which is only the type the chain opens with and would ignore the refinement (
Integer[1..10].input_typeis just Integer, but it accepts only 1..10). -
#initialize(left, right) ⇒ Intersection
constructor
A new instance of Intersection.
-
#value_preserving? ⇒ Boolean
An invariant, not a computation: Conjunction.build only produces an Intersection when both sides preserve the value, so
is_a?(Intersection)alone answers "is this a pure refinement?" — which Optimizer.reduce_step relies on.
Methods included from Conjunction
Methods included from Composable
#&, #/, #>>, #[], #absorb_input, #absorb_output, #as_node, #build, #check, #children, #defer, #fusable_step?, #fuse_with, #generate, #idempotent?, included, #input_type, #invalid, #invoke, #match, #metadata, #not, #output_type, #pipeline, #policy, resolve_operand, #static, #subtype_identity, #to_json_schema, #to_mermaid, #to_plumb_type, #to_s, #transform, #value, #where, #with, wrap, #|
Methods included from Callable
Constructor Details
#initialize(left, right) ⇒ Intersection
Returns a new instance of Intersection.
19 20 21 22 23 24 25 26 27 28 |
# File 'lib/plumb/intersection.rb', line 19 def initialize(left, right) @left = left @right = right @input_type = left.input_type # A meet IS its own output type — nothing to resolve through. The whole # difference from And. @output_type = self @children = [left, right].freeze freeze end |
Instance Method Details
#accepted_type ⇒ Object
A refinement accepts the constraint it actually passes — the right side's
resolved output — not its #input_type, which is only the type the chain opens
with and would ignore the refinement (Integer[1..10].input_type is just
Integer, but it accepts only 1..10). Deliberately the RIGHT CHILD's output and
not #output_type: that is the whole intersection including the left's gate,
and accepting against it would make #>> stricter than it has ever been.
41 |
# File 'lib/plumb/intersection.rb', line 41 def accepted_type = Plumb::Subtyping.resolved_output(children.last) |
#value_preserving? ⇒ Boolean
An invariant, not a computation: Conjunction.build only produces an Intersection
when both sides preserve the value, so is_a?(Intersection) alone answers "is
this a pure refinement?" — which Optimizer.reduce_step relies on.
33 |
# File 'lib/plumb/intersection.rb', line 33 def value_preserving? = true |