[erlang-questions] erlang *****

Andras Georgy Bekes bekesa@REDACTED
Fri Mar 14 12:57:31 CET 2008


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:
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)
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 
- 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.

> 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).


More information about the erlang-questions mailing list