Problem
With the default directive pack (#242), monad-transformer chains still do not collapse, and the 300-deep stress goldens grow slightly instead (Golden.LongStackBind 67,870 → 70,406 bytes, Golden.LongStateBind 75,735 → 78,463, Golden.LongWriterBind 57,000 → 57,422 in PR #327). The blocker is deliberate: directive derivation (#241) refuses to derive over a computed argument, because pasting bind (bindExceptT monadIdentity) — a dictionary built by applying the transformer's instance function — would re-run that construction at every one of ~300 sites (PR #327 added this work-free-argument guard after observing exactly that, +40% on the ExceptT golden). So the specialization stays a shared binding, the sites keep calling it, and the chain never meets the constructor folds.
Approach
Float the computed dictionary application to a top-level value binding during optimization: in a whole-program pipeline bindExceptT monadIdentity is a constant applicative form, so materializing it once as a named binding turns the derivation's argument into a plain reference — which the work-free guard accepts — and the existing cascade (derive, paste, resolve the field, fold) proceeds. This is the optimizer-side analogue of the float purs's own CSE emits for repeated dictionary applications in source. Recursive transformer dictionaries (the StateT-over-Except knot) additionally need the specialized instance methods unfolded through the newtype-shaped wrappers before the folds connect, so measure how far the float alone goes before deciding whether method-level specialization is also required.
Prerequisites / Relations
Follow-up to #242 / PR #327 (the guard that makes this the remaining blocker). Related: #326 (per-site dictionary field reads when the method is over budget — its sharing-repair pass would also clean up shapes this float exposes) and the #206 observation that recursive StateT dictionaries block the CPR-adjacent collapses.
Verification / Measurement
The three transformer stress goldens return to at most their pre-pack sizes, ideally collapsing like the Maybe/Either chains did; eval goldens unchanged; corpus size delta reported through the bench harness (#172) counters, which must not regress on any non-transformer artifact.
Problem
With the default directive pack (#242), monad-transformer chains still do not collapse, and the 300-deep stress goldens grow slightly instead (
Golden.LongStackBind67,870 → 70,406 bytes,Golden.LongStateBind75,735 → 78,463,Golden.LongWriterBind57,000 → 57,422 in PR #327). The blocker is deliberate: directive derivation (#241) refuses to derive over a computed argument, because pastingbind (bindExceptT monadIdentity)— a dictionary built by applying the transformer's instance function — would re-run that construction at every one of ~300 sites (PR #327 added this work-free-argument guard after observing exactly that, +40% on the ExceptT golden). So the specialization stays a shared binding, the sites keep calling it, and the chain never meets the constructor folds.Approach
Float the computed dictionary application to a top-level value binding during optimization: in a whole-program pipeline
bindExceptT monadIdentityis a constant applicative form, so materializing it once as a named binding turns the derivation's argument into a plain reference — which the work-free guard accepts — and the existing cascade (derive, paste, resolve the field, fold) proceeds. This is the optimizer-side analogue of the float purs's own CSE emits for repeated dictionary applications in source. Recursive transformer dictionaries (theStateT-over-Exceptknot) additionally need the specialized instance methods unfolded through the newtype-shaped wrappers before the folds connect, so measure how far the float alone goes before deciding whether method-level specialization is also required.Prerequisites / Relations
Follow-up to #242 / PR #327 (the guard that makes this the remaining blocker). Related: #326 (per-site dictionary field reads when the method is over budget — its sharing-repair pass would also clean up shapes this float exposes) and the #206 observation that recursive StateT dictionaries block the CPR-adjacent collapses.
Verification / Measurement
The three transformer stress goldens return to at most their pre-pack sizes, ideally collapsing like the Maybe/Either chains did; eval goldens unchanged; corpus size delta reported through the bench harness (#172) counters, which must not regress on any non-transformer artifact.