Do Notation
Long flat_map chains get hard to read. @do lets you write them as a generator:
yield a wrapped value to pull the inner value out, and the first failure
short-circuits the whole block.
from pyrula import do, Ok, Err
@dodef total(a: str, b: str): x = yield parse_int(a) # parse_int returns Ok/Err y = yield parse_int(b) return x + y
total("2", "3") # Ok(5)total("2", "nope") # Err(...), and the return never runsEach yield unwraps an Ok and binds the value, or stops at the first Err and
returns it. The body reads like straight-line code while keeping the error handling.
It works the same for Option and Try:
@dodef lookup(): user = yield find_user(uid) # Some/Nothing email = yield user.contact_email # Some/Nothing return emailTwo rules:
- Stick to one family per block. Mixing
OkandSomein the same@doraises aTypeError. - Use
@do_asyncforasync defblocks. Same semantics, awaits where needed.
from pyrula import do_async
@do_asyncasync def handler(): user = yield await fetch_user(uid) return user.nameScala equivalent
Section titled “Scala equivalent”@do is Scala’s for-comprehension. x = yield e is x <- e and return is yield,
with the first failure short-circuiting, exactly as a for { ... } yield over
Either/Option/Try desugars to flatMap and map.