[erlang-questions] Illegal Guard?

Trond Endrestøl <>
Fri Feb 5 16:25:25 CET 2016


On Fri, 5 Feb 2016 13:51+0100, Rad Gruchalski wrote:

> The reason for restricting the set of valid expressions is that 
> evaluation of a guard expression must be guaranteed to be free of 
> side effects.

Is there a way of convincing the Erlang compiler that a certain 
function is free of any side effects?

Below is what I believe to be a valid case.

While watching prof. Simon Thompson's Erlang Master Classes last year, 
he demonstrated in Master Class 1, Video 6, a parser where parts of 
the Erlang code was duplicated too much for my own taste.

Ref.: http://www.kent.ac.uk/elearning/themes/masterclasses.html

I typed my source file as I watched the video and tried to optimise 
the code by using macros.

Here's a couple of fragments from my own file. Notice the smaller 
classifier functions and the parse function both use macros to cope 
with (a) code duplication, and (b) the lack of user defined guard 
tests:

% Master Class 1, Video 6:

% I really wish we could convince the compiler to believe these three
% functions are without any side effects, and thus suitable as guard
% tests.

% Using macros is one way of managing the duplicate code.

-spec is_alpha(integer()) -> boolean().

-define(IS_ALPHA(Ch), $a =< Ch andalso Ch =< $z).

is_alpha(Ch) ->
    ?IS_ALPHA(Ch).

-spec is_num(integer()) -> boolean().

-define(IS_NUM(Ch), $0 =< Ch andalso Ch =< $9).

is_num(Ch) ->
    ?IS_NUM(Ch).

-spec is_white(integer()) -> boolean().

-define(HT,  9).
-define(LF, 10).
-define(VT, 11).
-define(FF, 12).
-define(CR, 13).
-define(SP, 32).

-define(IS_WHITE(Ch),
    (Ch == ?SP) orelse (Ch == ?HT) orelse (Ch == ?LF) orelse
    (Ch == ?CR) orelse (Ch == ?FF) orelse (Ch == ?VT)).

is_white(Ch) ->
    ?IS_WHITE(Ch).

%% Lines omitted

-spec parse(string()) -> {expr(), string()} | string().

parse([$( | Rest]) ->
    {E1, Rest1}      = parse(Rest),
    [Op | Rest2]     = parse(Rest1),
    {E2, Rest3}      = parse(Rest2),
    [$) | RestFinal] = parse(Rest3),
    {case Op of
         $+ ->
             {'add', E1, E2};
         $- ->
             {'sub', E1, E2};
         $* ->
             {'mul', E1, E2};
         $/ ->
             {'div', E1, E2}
     end,
    RestFinal};
parse([Ch | Rest]) when (Ch == $)) orelse (Ch == $+) orelse
                        (Ch == $-) orelse (Ch == $*) orelse
                        (Ch == $/) ->
    [Ch | Rest];
parse([Ch | Rest]) when ?IS_ALPHA(Ch) ->
    {Succeeds, Remainder} = get_while(fun is_alpha/1, Rest),
    {{var, list_to_atom([Ch | Succeeds])}, Remainder};
parse([Ch | Rest]) when ?IS_NUM(Ch) ->
    {Succeeds, Remainder} = get_while(fun is_num/1, Rest),
    {{num, list_to_integer([Ch | Succeeds])}, Remainder};
parse([Ch | Rest]) when ?IS_WHITE(Ch) ->
    {_Succeeds, Remainder} = get_while(fun is_white/1, Rest),
    parse(Remainder).

-- 
----------------------------------------------------------------------
Trond Endrestøl                     |     
ACM, NAS, NUUG, SAGE, USENIX        |     FreeBSD 10.3-P & Alpine 2.20


More information about the erlang-questions mailing list