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
-
#fuse_with(other) ⇒ Composable?
The fused container, or nil to leave the pair alone.
Instance Method Details
#fuse_with(other) ⇒ Composable?
Returns 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 |