-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Explore better typing for comprehensions / computational expressions #14
Comments
Ok, I think I understand the problem. Not sure if this can be solved, but I will see if there anything that can be done to fix this or workarounds. The current problem is that we are sort of being an advanced list comprehension, and the list needs to have a given type There is not any generic way (syntactic sugar) to achieve such unwrap / co-monadic / cata behavior in Python. In F# there is @effect.option
def fn() -> Generator[str, str, str]:
z: str
for x in Some(42.0):
for y in Some(int(x)):
z = yield from Some(str(y))
return z Nesting could actually be removed but we are seriously starting to misuse Python constructs 😬 @effect.option
def fn() -> Generator[str, str, str]:
z: str
for x in Some(42.0):
...
for y in Some(int(x)):
...
z = yield from Some(str(y))
return z Another way would be to (mis)use async / await e.g: @effect.option
async def fn() -> str:
x = await Some(42.0)
y = await Some(int(x))
z = await Some(str(y))
return z |
Hi. Very nice library :) I found this issue while trying to get this function to type check without the explicit annotations. This type checks, but the annotations are cumbersome: @effect.option
def maybe_add(maybe_a: Option[int], maybe_b: Option[int]) -> Option[int]:
a: int = yield from maybe_a
b: int = yield from maybe_b
return a + b ... this has no type annotations, but doesn't type check: @effect.option
def maybe_add(maybe_a: Option[int], maybe_b: Option[int]) -> Option[int]:
a = yield from maybe_a
b = yield from maybe_b
return a + b ... but while playing around, I found that this does type check: @effect.option
def maybe_add(maybe_a: Option[int], maybe_b: Option[int]) -> Option[int]:
yield from (a + b for a in maybe_a for b in maybe_b) Nice! And if we have more than a one-liner, this works too: @effect.option
def maybe_add(maybe_a: Option[int], maybe_b: Option[int]) -> Option[int]:
yield from (
a + b
for a in maybe_a
for b in maybe_b
) It's like a backward do-notation, which is close enough for me :) I'm type checking with pyright 1.1.155 |
Wow, that' really nice! Thanks for sharing! I'll see if I can add that to the docs somewhere |
@bgrounds This type checks correctly without annotating the variables. Also, return type is correctly typed to @OptionBuilder[int]()
def maybe_add(maybe_a: Option[int], maybe_b: Option[int]) -> Generator[int, int, Option[int]]:
a = yield from maybe_a
b = yield from maybe_b
return Some(a + b) |
Consider:
Currently, unless each expression has the same type, you're stuck either being untyped or
Any
-typed and manually typing each bound name. This is really unfortunate and not at all type-safe.Chaining a bunch of transformations of values within a functor or monad is a very common use of Haskell do-expressions, Scala for-expressions, and presumably (although i have no first hand knowledge) F# computational expressions.
It's really nice to be able to chain these and rely on types to ensure the correctness of each step.
With the current approach, it doesn't seem possible to type the individual layers of unwrapping differently unless they all share the same contained type (for the contravariant type parameter). This is really limiting the usefulness, alas.
Context: I'm trying to introduce some good foundations and abstractions for correctness at my company, and I think
Expression
could be a part of this based on its trajectory. However, the current limitations/ergonomics like this, combined with limitations inmypy
would make this a somewhat difficult sell, so I'm hoping there's a better approach or some ideas for improvement. Happy to assist where possible, but i'm definitely not an expert in python or python typing.The text was updated successfully, but these errors were encountered: