Either
Either is a result that’s one of two things: Ok with a value, or Err with an
error. You return it instead of raising, and the caller decides what to do.
from pyrula import Either, Ok, Err
def parse_port(raw: str) -> Either: if not raw.isdigit(): return Either.err(f"not a number: {raw!r}") port = int(raw) return Either.ok(port) if 0 < port < 65536 else Either.err(f"out of range: {port}")Transform without unwrapping
Section titled “Transform without unwrapping”map runs on the Ok side and skips Err. flat_map is the same but for functions
that themselves return an Either, so you don’t end up with Ok(Ok(x)).
parse_port("8080").map(lambda p: p + 1) # Ok(8081)parse_port("nope").map(lambda p: p + 1) # Err('not a number: ...'), untouchedparse_port("8080").flat_map(check_available) # check_available returns Eithermap_err transforms the error side. recover turns an Err back into an Ok.
Get a value out
Section titled “Get a value out”parse_port("8080").get_or_else(0) # 8080parse_port("nope").get_or_else(0) # 0
parse_port("99999").fold( lambda err: f"rejected: {err}", lambda port: f"using {port}",) # "rejected: out of range: 99999"
parse_port("nope").unwrap_or_raise(ValueError) # raises ValueError if Errfold handles both sides at once and is usually what you want at the edge of a
system, where the Either has to become a plain value.
Constructors and helpers
Section titled “Constructors and helpers”| Call | Result |
|---|---|
Either.ok(v) / Either.err(e) | Ok / Err |
Either.try_of(fn) | Ok(fn()), or Err if fn raises |
Either.cond(test, ok, err) | Ok(ok) if test else Err(err) |
Either.sequence([...]) | Ok of all values, or the first Err |
to_option() drops the error and gives you a Some/Nothing.
Typing
Section titled “Typing”Either[A, E] is a real generic, and Ok and Err are its subtypes. Annotate a result
with Either[A, E] and return either case:
def parse_port(raw: str) -> Either[int, str]: return Either.ok(int(raw)) if raw.isdigit() else Either.err(f"not a number: {raw!r}")Ok[A] and Err[E] work as annotations too, and isinstance(x, Either) is true for both.
Scala equivalent
Section titled “Scala equivalent”This is Scala’s right-biased Either[A, B]. Pyrula names the cases Ok/Err (Rust’s
spelling) where Scala uses Right/Left, and Ok/Err subclass Either just as
Right/Left do. The methods line up: map, flat_map (flatMap), fold,
get_or_else (getOrElse), recover, and to_option (toOption).