Module: Plumb::CovariantFusion

Included in:
ArrayClass, HashMap, StreamClass, TupleClass
Defined in:
lib/plumb/covariant_fusion.rb

Overview

MAP FUSION for covariant containers — the second functor law as a rewrite rule. Array[_], Tuple[…], Hash[K, _] and Stream[_] are covariant functors, so mapping f then g is mapping f >> g:

Array[f] >> Array[g]  ==  Array[f >> g]

The left traverses twice and materialises an intermediate copy; the right once. On a 50-element Array that is ~28% less time and 6 fewer allocations, growing with the collection. Hooked into #fuse_with, the container-level counterpart of Function's transform fusion.

SOUNDNESS. Carries its OWN proof rather than trusting the caller's: #>> type-checks the containers first but #/ deliberately does not, and both reach here. Every element pair must be provably composable.

That guard is what keeps ERROR behaviour intact — the one thing fusion could change. Two passes report stage by stage (a first-stage failure means the second never runs), while one pass could surface a second-stage error for element 2 beside a first-stage error for element 1. A provable boundary means the right element cannot reject what the left produced, so the two agree. An unprovable one (an opaque #check, a narrowing refinement) simply does not fuse.

Instance Method Summary collapse

Instance Method Details

#fuse_with(other) ⇒ Composable?

Returns the fused container, or nil to leave the pair alone.

Parameters:

Returns:

  • (Composable, nil)

    the fused container, or nil to leave the pair alone



28
29
30
31
32
33
34
35
36
# File 'lib/plumb/covariant_fusion.rb', line 28

def fuse_with(other)
  return nil unless self.class == other.class
  return nil if children.empty? || children.size != other.children.size

  pairs = children.zip(other.children)
  return nil unless pairs.all? { |mine, theirs| fusable_boundary?(mine, theirs) }

  with_children(pairs.map { |mine, theirs| mine >> theirs })
end