[erlang-questions] "Symmetrical" function

Richard O'Keefe <>
Mon Feb 16 22:21:38 CET 2009

```On 17 Feb 2009, at 4:13 am, David Mercer wrote:
> Why not just catch the function_clause error?

To make life really simple for the reader,
by making it really really obvious that the exception
is *deliberate*.
Also, being somewhat lazy, to avoid the trouble of
checking that it is the *right* function_clause exit.

>> Note that there is a behavioural difference:
>> the first version interleaves the swapped clauses with the
>> originals, while the second puts all the swapped clauses
>> after the originals.  The first approach can be modified
>> to get the effect of the second, but the second cannot
>> _easily_ be modified to get the effect of the first.
>
> Can you explain some more.  I don't understand the difference.

f(a, _) -> 1;
f(b, _) -> 2.

The "preprocessor" approach generates

f(_, a) -> 1;
f(a, _) -> 1;
f(_, b) -> 2;
f(b, _) -> 2.

The "exception" approach generates

f(X, Y) ->
try f1(X, Y)
catch throw:flip ->
try f1(Y, X)
catch throw:flip ->
erlang:error(function_clause, [X,Y])
end
end.

f1(a, _) -> 1;
f1(b, _) -> 2;
f1(_, _) -> throw(flip).

Now what happens if we ask for f(b, a)?
The version that interleaves the rules will return 1;
the version that first tries all the rules as written
and then tries all the rules swapped will return 2.

Since functional languages like ML, Erlang, and even Haskell
adopt a "first match" rule for functions, you cannot expect
re-ordering function rules to work.  But if you want to
automatically force a function to be symmetric, you *have*
to mix up two sets of rules somehow.  In addition to the
(B,A,B,A,...) and (A,A,...B,B,...) patterns, there are
obviously others like (A,B,A,B,...) and (B,B,...,A,A,...)
and many others.  In the absence of guards, detecting when
the order of interleavings might matter would be fairly
straightforward:  if {X1,Y1} and {Y2,X2} unify, there is
a problem.  (Here, {a,_} and {_,b} unify.)  Guards make it
a lot harder to tell.

```