-
Notifications
You must be signed in to change notification settings - Fork 3k
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
compiler: Add zip generators for comprehensions #8926
compiler: Add zip generators for comprehensions #8926
Conversation
CT Test Results 8 files 588 suites 1h 59m 45s ⏱️ Results for commit 899322d. ♻️ This comment has been updated with latest results. To speed up review, make sure that you have read Contributing to Erlang/OTP and that all checks pass. See the TESTING and DEVELOPMENT HowTo guides for details about how to run test locally. Artifacts// Erlang/OTP Github Action Bot |
19911a2
to
cac4be3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work! :-)
Does this need an EEP? There's also a question in my mind with how this interacts with #8625? In particular that EEP/feature argues that it's error prone to have values silently dropped from a comprehension - but this feature introduces even more cases where this happens if the zipped generators are not of equal length. It seems to me like those two features send opposing signals as to what kind of code and behaviour is expected and desirable. |
Yes. This implementation is for EEP 73. It will go through the EEP process. The forum post for discussion is here.
#8625 and zip generators are orthogonal features. For now, the implementation does not support strict generators, only because the syntax for strict generators isn't in master. I will add support for it after #8625 is merged. Implementation-wise it's not something too difficult to add. Design-wise, zip generators should support all kinds of generators in all comprehensions, including strict generators. The skipping behavior of individual generators within a zip generator is always respected. When a strict generator is zipped together with a relaxed generator, like Containing a mix of strict and relaxed generators isn't a reason that a zip generator having generators of different lengths. When evaluating a zip generator, 3 things can happen in every round: one element taken from every generator without skipping, one element taken from every generator and are all skipped, or |
@michalmuskala: I wouldn't say EEP 70 "argues that it's error prone to have values silently dropped from a comprehension". It merely says that silently dropping values "can hide the presence of unexpected elements". Whether non-matching elements are expected or not is up to the application. Both behaviours are desirable in different scenarios. But I agree that it should be stated, in EEP 73, how zip generators would interact with strict generators. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work! I am looking forward to using zip comprehensions in the code I write.
Here are some concrete examples where the relaxed behavior is useful. In the compiler, the SSA instructions have an argument list where each element in the list is either a
That said, we obviously also have many list comprehensions in the compiler where the strict behavior is appropriate. Here is an example from
(The current version of the code uses For more examples showing how zip comprehensions are useful, in this branch I've replaced the use of https://github.com/bjorng/otp/tree/bjorn/use-zip-comprehensions |
8da3330
to
2dc063c
Compare
7b62036
to
9f0e080
Compare
I know crossposting is bad; but i feel there are still more eyeballs here than in the forum. |
Pasted from the forum: I vaguely remembered that within OTP this year, Readability-wise, I prefer I could see how |
9f0e080
to
3486cca
Compare
lib/compiler/src/v3_core.erl
Outdated
make_refill([nomatch|RefillPats], Index, [_|Bodies], Args) -> | ||
make_refill(RefillPats, Index + 1, Bodies, Args); | ||
make_refill([RefillPat0|RefillPats], Index, [RefillBody|Bodies], {TailVars, LA, Mc, Sc}=Args) -> | ||
{H, [_|T]} = lists:split(Index, TailVars), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick:
{H, [_|T]} = lists:split(Index, TailVars), | |
{H, [_|T]} = split(Index, TailVars), |
lib/compiler/src/v3_core.erl
Outdated
end | ||
end. | ||
|
||
preprocess_skip(NomatchModes, NomatchPats, AccPats) -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't this (and _tail
) be done as part of preprocess_zip_generators/2
?
Edit: same for get_nomatch_total/1
.
We introduce zip generators for comprehensions to reduce the need for users to use lists:zip. Zip generators have the syntax of generator1 && ... && generatorN, where each generator can be a list, binary, or map generator. Zip generators are evaluated as if they are zipped to be a list of tuples. They can be mixed with all existing generators and filters freely. Two examples to show how zip generators is used and evaluated: 1> [{X,Y} || X <- [a,b,c] && Y <- [1,2,3]]. [{a,1},{b,2},{c,3}] 2> << <<(X+Y)/integer>> || X <- [1,2,3] && <<Y>> <= <<1,1,1>>, X < 3 >>. <<2,3>>
3486cca
to
899322d
Compare
We introduce zip generators for comprehensions to reduce the need for users to use lists:zip.
Zip generators have the syntax of
generator1 && ... && generatorN
, where each generator can be a list, binary, or map generator.Zip generators are evaluated as if they are zipped to be a list of tuples. They can be mixed with all existing generators and filters freely.
Two examples to show how zip generators is used and evaluated: