mapEither & mapEitherAsync
Run each event in its own raise scope: r.raise (and r.ensure / r.bind) becomes a Left, a normal return a Right.
Lecture
attempt is the boundary
conversion — it turns whatever is already on the error channel into
a Left. mapEither is the operator you
reach for after that, or on a clean source: each event
runs inside an either builder,
so you write straight-line Dart with r.ensure /
r.raise and the result of the whole map is
Either<E, R>. A failing event does not cancel
the source; later events still arrive.
A thrown exception stays on the error channel — that is the
either builder's contract, and it keeps
attempt the single place where a throw turns into a
value. When a callback both raises and throws, prefer
eitherCatching inside mapEither so one
Either comes out.
mapEitherAsync is the async twin: one event at a time,
like asyncMap. eitherAsync's rule carries
over: a raise must happen inside the awaited chain. A raise from an
unawaited future outlives the scope and surfaces as an unhandled
zone error instead of a Left.
A source error passes through both operators untouched. Convert
those with attempt upstream when you want them as
Lefts too.
Demo 1 · A raise becomes Left, a return becomes Right
Demo 2 · mapEitherAsync, one event at a time
Try it yourself
Exercise: a thrown exception stays on the error channel, and the chain continues past it.
attempt — the boundary that turns a throw into a Left ·
either builder — the same raise scope, on a single value ·
rights / separated — split the resulting Eithers