fix: preserve RuntimeError propagation and support plain function bodies - #272
Merged
Conversation
- Stop silently converting RuntimeError raised in effect bodies to zero(): the error now propagates to the caller, matching the async builder. - Support decorated functions without a yield statement: the body's return value is treated like a return statement (value -> return_(value), None -> zero()), instead of raising AttributeError. Adds regression tests for both behaviors to the option, result, seq, async-option, and async-result builder suites. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two P0 fixes to the computational-expression builder, aligning it with F# computation-expression semantics.
1.
RuntimeErrorraised in an effect body is no longer silently swallowedThe sync
Builder._sendhad anexcept RuntimeErrorbranch that converted the error intozero()— araiseinside an effect body produced a silent empty computation (e.g.Nothing) with no trace. Errors now propagate to the caller, matching the async builder.2. Decorated functions without a
yieldstatement are now supportedPlain function bodies (e.g.
def fn(): return 42) previously crashed withAttributeError. The return value is now treated like an F#returnstatement: a value is lifted withreturn_, andNonemaps tozero().Design notes
return(lifted withreturn_) rather thanreturn_from, becausereturn_is total and type-safe — a raw non-monad value never leaks into the monad.option,result,seq,async_option,async_result) were widened for LSP compatibility under pyright strict.Verification
None,RuntimeErrorpropagation)uv run pytest— 491 passeduv run ruff check expression/ && uv run ruff format --check expression/— cleanexpression/relative to themainbaseline