[erlang-questions] pattern match test operator

Andras Georgy Bekes bekesa@REDACTED
Tue Dec 4 18:24:40 CET 2007


Hi,

Almost every or every second day I bump into a situation when my 
proposed pattern-match-test-operator would be useful.

> What I feel is that such a notation isn't bringing enough to the
> language so that it's worth it.
OK, I'm trying to generalise the idea, to bring more.

Most of the time I'd use a pattern-match-test-operator, I'm about to do 
a disjunctive pattern matching. Something that could be solved 
by "fall-through á la C switch/case" like in the example written by 
somebody a few days ago:

days_in(jan, _);
days_in(mar, _);
days_in(may, _);
days_in(jul, _);
days_in(aug, _);
days_in(oct, _) -> 31;
days_in(dec, _);
days_in(apr, _);
days_in(jun, _);
days_in(sep, _);
days_in(nov, _) -> 30;
days_in(feb, common) -> 28;
days_in(feb, leap) -> 29.

We probably don't like the idea of fall-through, that's for imperative 
languages :-)

Let's follow a more scientific approach: Pattern matching basically 
tests whether a term is a member of a subset of terms. So a pattern 
describes a subset of terms. Basically guards do the same, they 
describe a subset of terms. With the use of guards, we can narrow the 
subsets that we describe by a pattern, we intersect the subsets. Now 
with guards you can do something that you cannot do with patterns: you 
can do all the set-operations (union, intersection, subtraction) with 
the use of ',', ';' and all the boolean operators).

Now let's try to extend patterns with the set operations.

- Intersecting the sets of patterns is trivial, for example, the 
intersecion of the patterns {a,_,_} and {_,b,_} gives the pattern 
{a,_,_}={_,b,_}

- Union: I think there is no '|' operator in Erlang, so:
{a,_,_} UNION {_,b,_} could be written: {a,_,_}|{_,b,_}
Now this was easy, let's do something tricky:

{a,X,_} when is_integer(X) | {X,b,_} when X>3

This would match if either of the patterns match. The binding rule for 
variables is well-defined, we already can have variables bound to 
different values in different branches of an 'if', 'case', or 'receive' 
expression.

- Subtraction: it could be done by the pattern match test operator!
For example:
({a,X,Y} when is_integer(X) | {X,b,Y} when X>3) when       
                                                not(Y~={_,undefined})

Probably there is a better sintax for all of this.

About the semantics: all this is possible with some parse 
transformations. For example a pattern match with the above pattern: 
({a,X,Y} when is_integer(X) |
 {X,b,Y} when X>3) when not(Y~={_,undefined}) = VALUE

is (logically) equivalent to

begin
   case VALUE of
      {a,X,Y} when is_integer(X) ->
         ok;
      {X,b,Y} when X>3 ->
	ok;
      _ ->
        erlang:error({badmatch,VALUE})
   end,
   case Y of
      {_,undefined}->
         erlang:error({badmatch,VALUE});
      _->
         VALUE
   end
end

Now writing this parse transform is not impossible, but it could not use 
an elegant syntax and would be slower than a compiled implementation. 
But the real disadvantage: You cannot use it in 'real' patterns 
(function heads, case and receive expressions...) only in pattern-match 
expressions.

Is this bringing enough to the language so that it's worth (considering) 
it?

	Georgy



More information about the erlang-questions mailing list