Either<L, R>.binding constructor
- @monadComprehensions R block(
- EitherEffect<
L> effect
- EitherEffect<
Monad comprehension.
Syntactic sugar do-notation.
Although using flatMap openly often makes sense, many programmers prefer a syntax
that mimics imperative statements (called do-notation
in Haskell
, perform-notation
in OCaml
,
computation expressions
in F#
, and for comprehension
in Scala
).
This is only syntactic sugar that disguises a monadic pipeline as a code block.
Calls the specified function block
with EitherEffect as its parameter and returns its Either.
When inside a Either.binding block, calling the EitherEffect.bind function will attempt to unwrap the Either and locally return its Right.value. If the Either is a Left, the binding block will terminate with that bind and return that failed-to-bind Left.
You can also use BindEitherExtension.bind instead of EitherEffect.bind for more convenience.
Example
class ExampleError {}
Either<ExampleError, int> provideX() { ... }
Either<ExampleError, int> provideY() { ... }
Either<ExampleError, int> provideZ(int x, int y) { ... }
Either<ExampleError, int> result = Either<ExampleError, int>.binding((e) {
int x = provideX().bind(e); // or use `e.bind(provideX())`.
int y = e.bind(provideY()); // or use `provideY().bind(e)`.
int z = provideZ(x, y).bind(e); // or use `e.bind(provideZ(x, y))`.
return z;
});
NOTE
- Do NOT catch ControlError in
block
. - Do NOT throw any errors inside
block
. - Use Either.catchError, Either.catchFutureError or Either.catchStreamError to catch error, then use EitherEffect.bind to unwrap the Either.
/// This function can throw an error.
int canThrowAnError() { ... }
// DON'T
Either<ExampleError, int> result = Either<ExampleError, int>.binding((e) {
int value = canThrowAnError();
});
// DO
ExampleError toExampleError(Object e, StackTrace st) { ... }
Either<ExampleError, int> result = Either<ExampleError, int>.binding((e) {
int value = Either<ExampleError, int>.catchError(
toExampleError,
canThrowAnError
).bind(e);
});
Implementation
factory Either.binding(
@monadComprehensions R Function(EitherEffect<L> effect) block) {
final eitherEffect = _EitherEffectImpl<L>(_Token());
try {
return Either.right(block(eitherEffect));
} on ControlError<L> catch (e) {
if (identical(eitherEffect._token, e._token)) {
return Either.left(e._value);
} else {
rethrow;
}
}
}