From 739cdfb6095f7683e537e6b4e79f05a3ec23630b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 24 Feb 2023 11:40:59 +0100 Subject: [PATCH] Address a few omissions in documentation of comprehensions * Document that variables bound in a generator expression is not visible outside that expression. * Document the failure modes for filters. Closes #6454 --- system/doc/reference_manual/expressions.xml | 76 +++++++++++++++++---- 1 file changed, 61 insertions(+), 15 deletions(-) diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml index 51d23baacfff..c0698e414002 100644 --- a/system/doc/reference_manual/expressions.xml +++ b/system/doc/reference_manual/expressions.xml @@ -1985,29 +1985,31 @@ KeyPattern := ValuePattern <- MapExpression marker="stdlib:maps#iterator/2">maps:iterator/2.

A filter is an expression that evaluates to - true or false, or a - guard expression. - If the filter is not a guard expression and evaluates - to a non-Boolean value Val, an exception - {bad_filter, Val} is triggered at runtime.

+ true or false.

The variables in the generator patterns shadow previously bound variables, including variables bound in a previous generator pattern.

-

A list comprehension returns a list, where the lists elements are the +

Variables bound in a generator expression are not visible outside the expression:

+ +
+1> [{E,L} || E <- L=[1,2,3]].
+* 1:5: variable 'L' is unbound
+ +

A list comprehension returns a list, where the list elements are the result of evaluating Expr for each combination of generator elements for which all filters are true.

-

A bit string comprehension returns a bit string, which is +

A bit string comprehension returns a bit string, which is created by concatenating the results of evaluating BitStringExpr for each combination of bit string generator elements for which all filters are true.

-

A map comprehension returns a map, where the map elements are - the result of evaluating KeyExpr and ValueExpr for - each combination of generator elements for which all filters are - true. If the key expressions are not unique, the last occurrence - is stored in the map.

+

A map comprehension returns a map, where the + map elements are the result of evaluating KeyExpr and + ValueExpr for each combination of generator elements for + which all filters are true. If the key expressions are not unique, + the last occurrence is stored in the map.

Examples:

@@ -2059,6 +2061,10 @@ KeyPattern := ValuePattern <- MapExpression [{a,1},{a,2},{b,1},{b,2},{c,1},{c,2}] +

More examples are provided in + + Programming Examples.

+

When there are no generators, a comprehension returns either a term constructed from a single element (the result of evaluating Expr) if all filters are true, or a term constructed from @@ -2072,9 +2078,49 @@ KeyPattern := ValuePattern <- MapExpression 2> [x || is_integer(x)]. [] -

More examples are provided in - - Programming Examples.

+

What happens when the filter expression does not evaluate to + a boolean value depends on the expression:

+ + +

If the expression is a guard expression, failure + to evaluate or evaluating to a non-boolean value is equivalent + to evaluating to false.

+ +

If the expression is not a guard expression and + evaluates to a non-Boolean value Val, an exception + {bad_filter, Val} is triggered at runtime. If the + evaluation of the expression raises an exception, it is not + caught by the comprehension.

+
+ +

Examples (using a guard expression as filter):

+ +
+1> List = [1,2,a,b,c,3,4].
+[1,2,a,b,c,3,4]
+2> [E || E <- List, E rem 2].
+[]
+3> [E || E <- List, E rem 2 =:= 0].
+[2,4]
+ +

Examples (using a non-guard expression as filter):

+ +
+1> List = [1,2,a,b,c,3,4].
+[1,2,a,b,c,3,4]
+2> FaultyIsEven = fun(E) -> E rem 2 end.
+#Fun<erl_eval.42.17316486>
+3> [E || E <- List, FaultyIsEven(E)].
+** exception error: bad filter 1
+4> IsEven = fun(E) -> E rem 2 =:= 0 end.
+#Fun<erl_eval.42.17316486>
+5> [E || E <- List, IsEven(E)].
+** exception error: an error occurred when evaluating an arithmetic expression
+     in operator  rem/2
+        called as a rem 2
+6> [E || E <- List, is_integer(E), IsEven(E)].
+[2,4]