io::lines() Carries Its Failure to the WalkStatus: Accepted
Date: September 27, 2026
Answers: #182, a lazy walk of io::lines() has no shape
Refines: ADR-172 D3 and D5 (the lazy walks of a pausing
sequence, refused from the lowering)
Related: ADR-233 (a sequence whose step pauses), ADR-025 D1 (a walk of a failing sequence fails at
the walk), Part I 6.4 (a failure is never a shorter list)
ADR-233 gives a sequence whose step pauses its lazy walks, on
nikaia_std::seq::Step. One sequence in std has a step that also fails:
let long = io::lines().map(fn(l) { l.len() }).filter(fn(n) { n > 80 }).collect()
Below, a step of
io::lines() is the line or the failure, so an adapter over it has to decide
where the failure goes.
io::Lines is a Step whose item is the line or the failure, and every lazy
walk Seq has but rev — map, filter, take, skip, step_by, zip,
with a plain lambda or one that pauses — hands back another sequence of the
same kind, nikaia_std::seq::Failing. A lambda is handed the line; a
failure passes through it untouched. What walks the result is where the
failure lands, which is where ADR-025 D1 already put it:
collect, count, nth and join end at the first failure and hand it
back, and the ? after them is the one the eager walk of io::lines() has
had since ADR-172 D5;for over it takes each step’s ?, so the lines before the failure are
handled and the failure leaves the function after them.So map of a failing sequence is a failing sequence: the type of the result
keeps the receiver’s throws, and a function walking it says throws as for
the lines themselves (NK2701). A failure is never a shorter list
(Part I 6.4): take, skip and step_by count a failure as a step, and the
walk ends at it all the same.
With D1, no entry that hands back a sequence lacks a pausing form, and the lowering’s refusal for one (ADR-172 D5) is not reached. It stays, worded for the next entry that is added without one, rather than being taken out and put back.