From c67d8f36dba8ee983299daf7b12113b23ddc0fa1 Mon Sep 17 00:00:00 2001 From: lucioleKi Date: Wed, 6 Nov 2024 10:07:19 +0100 Subject: [PATCH] Updated EEP for behaviors with strict generators --- eeps/eep-0073.md | 56 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/eeps/eep-0073.md b/eeps/eep-0073.md index 854bc21..c520565 100644 --- a/eeps/eep-0073.md +++ b/eeps/eep-0073.md @@ -1,5 +1,5 @@ Author: Isabell Huang - Status: Draft + Status: Final/28.0 Implemented in OTP release 28 Type: Standards Track Created: 21-Sep-2024 Erlang-Version: OTP-28.0 @@ -73,7 +73,7 @@ list of tuples. Variable bindings and pattern matching within a zip generator works as expected, as `Nm` is supposed to bind to the same value in `{Nm,P}` and `{Nm,S}`. If the binding fails, then one element from each of the 3 generators is skipped. (If a strict generator is used, then the comprehension -fails with exception `badmatch`, as specified in EEP-70.) +fails with an exception, as specified in [Error Behaviors](#error-behaviors).) In summary, zip generators remove the user's need to call the zip function within comprehensions and allows for any number of lists to be zipped at once. @@ -138,6 +138,23 @@ filtered out from the resulting list. [{X, Y} || X <- [a, b, c] && <> <= <<2, 4, 6>>, Y =/= 2]. +The skipping behavior of individual generators within a zip generator is always +respected. When strict generators are present in a zip generator, during every +round of evaluation, all strict generators will be evaluated even if another +relaxed generator already causes the result to be skipped. + +For example, the following comprehension has a zip generator containing a +strict generator and a relaxed generator. + + [{X, Y} || {a, X} <:- L1 && {b, Y} <- L2] + +It will `badarg` if pattern matching for `{a, X}` fails, for example, when +`L1 = [{a, 1}, {bad, 2}, {a, 3}]`. It will simply skip 1 item from `L1` and +1 item from `L2` if pattern matching for `{b, Y}` fails, for example, when +`L2 = [{b, 1}, {bad, 2}, {b, 3}]`. The attempt of matching `{a, X}` will +be made every round, regardless of generators ordering and whether other +pattern matchings succeed. + Comparing to using helper functions, there is one advantage of using a zip generator: The Erlang compiler does not generate any tuple when a zip generator is translated into core Erlang. The generated code reflects the @@ -170,7 +187,7 @@ all generators. For example, this comprehension will crash at runtime. - [{X,Y} || X <- [1,2,3] && Y <- [1,2,3,4]]. + [{X,Y} || X <- [1,2,3] && Y <- [1,2,3,4]]. The resulting error tuple is `{bad_generators,{[],[4]}}`. This is because when the comprehension crashes, the first list in the zip generator has @@ -183,6 +200,35 @@ different length comparing to others. The proposed error message aims to gives the most helpful information without imposing extra burden on the compiler or runtime. +Failed Strict Generator in a Zip Generator +----------------- + +When a zip generator crashes because at least one strict generators contained +in it fails, the resulting error tuple is of the same format as when generators +are of different lengths. Its first element is the atom `bad_generators`, and +the second element is a tuple containing remaining data from all generators. + +For example, this comprehension will crash at runtime, because `bad` cannot +match the pattern `{ok,A}`. + + [A + B || {ok,A} <:- [bad, {ok,1}] && B <- [2,3]]. + +The resulting error tuple is `{bad_generators,{[bad, {ok,1}],[2,3]}}`. Although +strict generators alone fail with exception `badmatch`, as specified in +[EEP-70][4], it is not plausible to use the same exception in zip generators, +due to difficulty in distinguishing between `badmatch` and `bad_generators` +errors. + +In the following example, the comprehension will crash at runtime, either for +the failed strict generator, or for two generators of different lengths. + + [A + B || {ok,A} <:- [bad] && B <- []]. + +The emitted error message is `{bad_generators,{[bad],[]}}`. We do not +distinguish between the two errors, and instead always output all remaining +data in the generators. The user can examine the remaining data and see that +the first generator fails matching, and the second generator is empty. + Non-generator in a Zip Generator ----------------- @@ -212,12 +258,12 @@ this addition. Reference Implementation ======================== -[compiler: Add zip generators for comprehensions][1] contains the implementation -for zip generators. +[PR-8926][1] contains the implementation for zip generators. [1]: https://github.com/erlang/otp/pull/8926 [2]: https://downloads.haskell.org/~ghc/5.00/docs/set/parallel-list-comprehensions.html [3]: https://docs.racket-lang.org/reference/for.html +[4]: https://www.erlang.org/eeps/eep-0070 Copyright =========