[erlang-questions] Can we change the semantics of match expressions in comprehensions?

Matthew Dempsky matthew@REDACTED
Mon Feb 4 21:31:49 CET 2008


I'd like to propose a change to the semantics of match expressions as
filters in list and bit comprehensions.  Currently, all filter
expressions are evaluated and expected to return true or false or else
an error is raised.

I suggest special casing match expressions as filters.  If a filter is
of the form Pat = Expr, Expr is evaluated normally, and whether the
result can be matched to Pat determines whether the comprehension
continues down this path.  E.g., this change would allow [B || {1,B} =
A <- [{1,2},{2,3},{1,3}]] to be rewritten as [B || A <-
[{1,2},{2,3},{1,3}], {1,B} = A].  It would also allow list
comprehensions like [B || A <- List, {ok, B} = foo(A)].

I doubt this change will affect any existing code.  Right now, filters
like {1,B} = A would unconditionally raise bad_filter errors.  The
only match expression filter that would not result in bad_filter
errors are "true = Expr", "false = Expr", and "Var = Expr"; and I find
it highly unlikely that these expressions would be in use as
comprehension filters.

However, if there is concern about this change in semantics, erl_lint
could be changed to emit warnings about code using those expressions
for a few releases before the semantics are changed.

Below is a proof-of-concept patch to implement this change for
erl_eval, which allows you to play with the new semantics at the
command-line.


--- erl_eval.erl.orig	2008-02-04 11:53:07.000000000 -0800
+++ erl_eval.erl	2008-02-04 12:10:19.000000000 -0800
@@ -576,12 +576,21 @@
 		{value,false,_} -> Acc
 	    end;
 	false ->
-	    case expr(F, Bs0, Lf, Ef, none) of
-		{value,true,Bs1} -> CompFun(Bs1);
-		{value,false,_} -> Acc;
-		{value,V,_} ->
-                    erlang:raise(error, {bad_filter,V}, stacktrace())
-	    end
+            case F of
+                {match,_,Lhs,Rhs0} ->
+                    {value,Rhs,Bs1} = expr(Rhs0, Bs0, Lf, Ef, none),
+                    case match(Lhs, Rhs, Bs1) of
+                        {match,Bs2} -> CompFun(Bs2);
+                        nomatch -> Acc
+                    end;
+                _ ->
+                    case expr(F, Bs0, Lf, Ef, none) of
+                        {value,true,Bs1} -> CompFun(Bs1);
+                        {value,false,_} -> Acc;
+                        {value,V,_} ->
+                            erlang:raise(error, {bad_filter,V}, stacktrace())
+                    end
+            end
     end.



More information about the erlang-questions mailing list