This is neat. It reminds me of an silly project [0] I made a while back to implement do-notation in python. In OP's project you still end up with code that's basically this:
y = (Maybe(just=x) if x > 0 else Maybe()).bind(lambda a:
Maybe(just=x*a) .bind(lambda b:
Maybe.mreturn(a+b)))
It's functionally sound and standard, but ergonomically painful. I built a really fun horrible hack to allow you to write that instead as this:
with do(Maybe) as y:
a = Maybe(just=x) if x > 0 else Maybe()
b = Maybe(just=x*a)
mreturn(a+b)
It swaps out the assignment operator `=` in the `with do()` block for the monadic bind operation, which you might be used to seeing as `<-`.
You just need to use my @with_do_notation decorator, which just completely rewrites your function using the ast library wherever it finds a block of `with do(SomeClass) as variable:`. I was even able to write ergonomically nice parser combinators [1] that would actually work pretty well if python had tail call optimization.
You shouldn't use it but it was great fun and opened my eyes to the ways you can abuse python if you really wanted to. Using decorators to introspect and completely rewrite functions is a fun exercise.
Your example isn't using "y", so you should also be able to drop the " as y" part (unless the AST hack requires it for some reason).
Edit: Oh, nevermind - the "y" is how you access it after the with statement. Weird for python, but it makes sense given the rewritten version. I was thinking your version would have a non-rewritten "result = something" within the with block in a real use, but that's not what it's doing.
Heh, yup, it's part of the hackiness of it all. "with do(MyMonadClass) as my_variable: <some code>" equates to haskell's "myVariable = do <some code>". I can't remember why the MyMonadClass part was necessary. Maybe for the mreturn.
You just need to use my @with_do_notation decorator, which just completely rewrites your function using the ast library wherever it finds a block of `with do(SomeClass) as variable:`. I was even able to write ergonomically nice parser combinators [1] that would actually work pretty well if python had tail call optimization.
You shouldn't use it but it was great fun and opened my eyes to the ways you can abuse python if you really wanted to. Using decorators to introspect and completely rewrite functions is a fun exercise.
[0] https://github.com/imh/python_do_notation
[1] https://github.com/imh/python_do_notation/blob/master/parser...