diff --git a/eeps/eep-0073.md b/eeps/eep-0073.md index f05ec72..96c458b 100644 --- a/eeps/eep-0073.md +++ b/eeps/eep-0073.md @@ -33,9 +33,9 @@ resulting list has length 4 when the two input lists both have length 2. In contrast, parallel list comprehension (also known as zip comprehension) evaluates qualifiers (a generalization of lists) in parallel. Qualifiers are first "zipped" together, and then evaluated. Many functional languages -([Haskell][2], [Racket][3], etc.) and non-functional languages (Python etc.) support -this variation. Suppose the two lists in the example above are evaluated as -a zip comprehension, the result would be `[{1,3}, {2,4}]`. +([Haskell][2], [Racket][3], etc.) and non-functional languages (Python etc.) +support this variation. Suppose the two lists in the example above are +evaluated as a zip comprehension, the result would be `[{1,3}, {2,4}]`. Zip comprehensions allow the user to conveniently iterate over several lists at once. Without it, the standard way to accomplish the same task in Erlang @@ -54,11 +54,33 @@ can be mixed freely with all existing generators and filters. Zip comprehension then becomes a special case of comprehension where only zip generators are used. -In summary, zip generator removes the user's need to call the zip function -and allows for any number of lists to be zipped at once. It can be used in -list, binary, and map comprehensions, and mixed freely with all existing -generators and filters. Internally, the compiler does not create any -intermediate data structure, therefore also removing the need of deforestation. +Within the OTP codebase, there are many uses of `lists:zip` within comprehensions. +All of them can be simplified by zip generators using `&&` syntax. For example, +The `yecc.erl` in parsetools contains the following comprehension (external +function calls and irrelevant fields redacted for readability): + + PartDataL = [#part_data{name = Nm, eq_state = Eqs, actions = P, states = S} + || {{Nm,P}, {Nm,S}, {Nm,EqS}} <- + lists:zip3(PartNameL, PartInStates, PartStates)]. + +When using zip generators, the comprehension is rewritten to: + + PartDataL = [#part_data{name = Nm, eq_state = Eqs, actions = P, states = S} + || {Nm,P} <- PartNameL && {Nm,S} <- PartInStates && {Nm,EqS} <- PartStates]. + +By using zip generators, the compiler avoids the need to build the intermediate +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.) + +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. +It can be used in list, binary, and map comprehensions, and mixed freely with +all existing generators and filters. Internally, the compiler does not create +any intermediate data structure, therefore also removing the need of +deforestation. Specification ========================