[erlang-questions] erlang *****
Andras Georgy Bekes
bekesa@REDACTED
Fri Mar 14 12:57:31 CET 2008
Hi,
I was following this topic and was waiting for the right time to throw
in my ideas :-)
> case X of
> _ when X == abc; X == xyz ->
> do_abc_or_xyz();
> I don't much like the _ when business.
Yes, I agree, but while you suggest using 'if' in similar cases, I
suggest a different solution.
The point here is that you want do have the same result in several
cases, but you can't do it with the 'case' construct. You use guards
instead of pattern matching, because the logic "OR" operator (;) can be
used with guards, while it cannot be used with patterns.
Pattern matching basically tests whether a term is a member of a subset
of terms. So a pattern describes a subset of terms. Patterns and guards
together do the same, they describe a subset of terms by deselecting
values that don't satisfy the guards.
The ; operator means union. The pattern
Pattern when Guard1; Guard2
describes the subset of terms:
(Pattern when Guard1) UNION (Pattern when Guard2)
Why don't we extend the notion of patterns to somehow describe the union
set operation?
We already can describe the intersection of patterns:
Pattern1=Pattern2
describes the subset
Pattern1 INTERSECTION Pattern2
I think there is no '\/' operator in Erlang, so
Pattern1 \/ Pattern2 could mean Pattern1 UNION Pattern2
Let's see some example uses:
{a,_,_} \/ {b,_,_}
[ a \/ b | Tail ]
{a,X,_} when is_integer(X) \/ {X,b,_} when X>3
The union of patterns matches if (at least) one of the patterns matches.
The union pattern binds only the names that are present in each pattern.
Other names are considered unsafe.
There is one more basic set operation: subtraction. With the use of
guards, you can subtract a subsets from a set described by a pattern:
A positive guard subtracts the terms that don't satisfy the guard,
negated guards subtract the terms that do.
But you cannot subtract a subset of terms described by a pattern.
I've already suggested a pattern-match-test operator. It does have other
uses as well, but it is also useful for subtracting subsets:
Let "Pattern ~= Expression" semantically mean
case Expression of Pattern -> true; _ -> false end
You'll want to use this in guards:
Pattern1 when not (Pattern2 ~= Pattern1)
means
Pattern1 MINUS Pattern2
Of course the syntax might seem terrible, there are probably better
symbols for set operations.
The addition of these two constructs would:
- amend patterns to be a complete syntax for describing a subset of
terms
- allow programmers to avoid duplicated code
- only _extend_ Erlang, not changing the behaviour of existing programs
- almost entirely obsolate the 'if' construct
However, in order to fully obsolate 'if', we'd need some case-like
construct that can check multiple expressions.
This is what Richard A. O'Keefe suggested:
> This can be handled pretty closely by
> case E1 of true -> S1;
> case E2 of true -> S2;
> ...
> case En of true -> Sn
> end ... end end
> All that's really needed here is an equivalent of Algol 68's "ouse",
> which was to 'case' as 'elif' was to 'if'. So add it!
>
> case E1 of true -> S1
> ouse E2 of true -> S2
> ...
> ouse En of true -> Sn
> end
I don't have a better syntax proposal, but I completely agree.
Besides:
> The differences really boil down to this:
> guards are for INDEXING.
Yes, patterns and guards not only have to be expressive, they also have
to be very efficient.
You might think that the above idea of extending pattern matching with
the union operator ruins the clever indexing of patterns. It does not,
because the decision diagram does not have to be a tree, i.e. union'd
patterns might have independent paths in the decision diagram, but end
in the same leaf (function or case clause).
Georgy
More information about the erlang-questions
mailing list