Class: Plumb::Intersection

Inherits:
Object
  • Object
show all
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

Methods included from Conjunction

build, #call, #with_children

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

#call, #parse, #resolve

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_typeObject

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.

Returns:

  • (Boolean)


33
# File 'lib/plumb/intersection.rb', line 33

def value_preserving? = true