dbrattli / OSlash

Functors, Applicatives, And Monads in Python
MIT License
708 stars 50 forks source link

do notation, monadic guard #12

Closed Technologicat closed 3 years ago

Technologicat commented 5 years ago

Here's an attempt at do-notation for Python. It seems none of the monad libraries currently provide that.

Example:

from oslash import List, do, let, guard

r = lambda low, high: List.from_iterable(range(low, high))
out = do(let(z=r(1, 21)),               # let is "<-"
         let(x=lambda e: r(1, e.z+1)),  # uses env via "lambda e: ..."
         let(y=lambda e: r(e.x, e.z+1)),
         lambda e: guard(List, e.x*e.x + e.y*e.y == e.z*e.z),
         lambda e: List.unit((e.x, e.y, e.z)))
print(out)

The syntax is loosely modeled after letrec in unpythonic, which in turn was inspired by [1] [2] [3].

This is pure Python 3.4, implemented essentially as a code generator. The client code would look cleaner if this was a syntactic macro instead (using MacroPy3), but this version makes do (no pun intended) with Python's builtin capabilities.

Comments welcome.

Also, I think guard is useful, especially with List. Where should it go in OSlash?

Technologicat commented 5 years ago

FWIW, since posting this, I've added a MacroPy3-based do-notation to unpythonic. Since unpythonic is not really a monad library, it's currently hard-coded for the List monad (but this limitation is easily removed).

See the forall syntax transformer in forall.py. It's much cleaner and much less hacky than what is possible without macros.

(For comparison, the same feature is implemented without macros in the badly named amb.py, but the code in this PR already contains a clean minimal version of the relevant parts of that.)

If you're interested in the macro approach, it could be adapted here.

sobolevn commented 4 years ago

@Technologicat you might be interested in this issue: https://github.com/dry-python/returns/issues/392

We are working on typed do-notation in Python, and I would love to hear your ideas about it!

dbrattli commented 3 years ago

This is pure gold! Sorry for taking so long. Been lost in F# for a long time. Planning to merge this soon.

dbrattli commented 3 years ago

I'm closing this as the commits here have now been merged into master through https://github.com/dbrattli/OSlash/pull/19 since I didn't have write access to the PR. Again, thanks for your contribution to OSlash!