[erlang-questions] Floating guard sequences

Michael Radford mrad-direct-erlang@REDACTED
Tue Feb 17 23:13:50 CET 2009

This is a very preliminary proposal to extend Erlang's guard
syntax (based on an idea I briefly mentioned in another thread).
I'd like to hear people's reactions....if there is interest, and
if the OTP team doesn't say it's impossible for some reason, I'd
be happy to write an EEP.

So, what if...

Anywhere [*] in a function parameter list, the pattern of a case
(or try or receive) clause, or the left-hand side of a match (=)
expression, a "floating guard sequence" was allowed:

        (when GUARD-SEQUENCE)

The floating guard sequence is just syntactic sugar for the same
guard sequence promoted to the normal guard position of the
enclosing expression.  Or in the case of a plain match, promoted
to a following 'if' as described below.  When there is more than
one floating guard sequence (or they are mixed with normal
guards), they are combined in the obvious way into disjunctive
normal form.

([*] "Anywhere" suitably restricted to make parsing easy, for
example, maybe only following a complete term, not following ',',
'|', '||', operators, etc.)


1. In a function parameter list:

        f ({ X (when X < 0; X > 3), [Y (when Y > 0, Y < 7) | Ys] }) -> BODY;

would be equivalent to:

        f ({X, [Y | Ys]}) when X < 0, Y > 0, Y < 7
                             ; X > 3, Y > 0, Y < 7 -> BODY;

2. Similarly, in a case pattern:

        case EXPR of
          { X (when X < 0; X > 3), [Y (when Y < 0; Y > 7) | Ys] } ->

would be equivalent to:

        case EXPR of
          {X, [Y | Ys]} when X < 0, Y < 0 ; X < 0, Y > 7
                           ; X > 3, Y < 0 ; X > 3, Y > 7 ->

3. Finally, floating guard sequences in the LHS of a match would
be equivalent to wrapping all following expressions in the same
sequence in an 'if' with the same guards, and failing with
'badmatch' instead of 'if_clause':

        { X (when X < 0; X > 3), [Y (when Y > 0, Y < 7) | Ys] } = f(Z),

would be equivalent to something like:

        __Match_1234 = {X, [Y | Ys]} = f(Z),
          X < 0, Y > 0, Y < 7 ; X > 3, Y > 0, Y < 7 ->
          true ->
            erlang:error ({badmatch, __Match_1234})

I see the main advantages of this syntax as: (1) often being more
concise, and (2) allowing guard tests that are conceptually part
of the "type" of a variable to be right next to the location where
the variable is defined.  (In addition, this would allow macros
that expand to patterns to include guards.)

Also, allowing any form of guard on an '=' match would make things
much easier in situations where you want to assert some property
of the matched value, since the {badmatch, Value} exception
contains the value that failed the guard.  Currently, you have to
introduce a case statement to get an exception containing the
value that failed a guard.


More information about the erlang-questions mailing list