[erlang-questions] pattern match test operator
Andras Georgy Bekes
<>
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