[erlang-questions] Erlang elseif

Richard O'Keefe ok@REDACTED
Fri Nov 21 03:15:58 CET 2008


>> this but I could not find anything that answered my question. The  
>> thing is
>> that I want a general way to branch the execution of my code based  
>> on the
>> result on an expression. Very similar to how if works but I want to  
>> be able
>> to test expressions and not only guards. If you're thinking "then  
>> you have
>> case" now look below at function elseif2() and you'll see my point.

Given that we have length(List) in guards, which definitely breaks
the "guards are fast" guideline, it would be tempting to allow
member(Term, List) in guards as well.
>> 42> e:elseif4($Q).
>> Member of capital
>>
>> -define(CAPS, "QWERTY").
>> -define(SMALL, "qwerty").
>> -define(NUMS, "123456").
>>
>> %% The wierd not-so-Erlang way
>> elseif1(A) ->
>>   lists:member(A,?CAPS)
>>       andalso begin
>>                   io:format("Member of capital\n"),
>>                   true
>>               end
>>       orelse
>>       lists:member(A,?SMALL)
>>       andalso begin
>>                   io:format("Member of small\n"),
>>                   true
>>               end
>>       orelse
>>       lists:member(A,?NUMS)
>>       andalso begin
>>                   io:format("Member of nums\n"),
>>                   true
>>               end
>>       orelse
>>       io:format("Not a member").

	ei(Letter) when is_integer(C) ->
	    io:format(eic(Letter)).

	eic(C) when C == $Q ; C == $W ; C == $E
                   ; C == $R ; C == $T ; C == $Y
	    -> "Member of capital\n";
	eic(C) when C == $q ; C == $w ; C == $e
		  ; C == $r ; C == $t ; C == $y
	    -> "Member of small\n";
	eic(C) when C == $1 ; C == $2 ; C == $3
	          ; C == $4 ; C == $5 ; C == $6
	    -> "Member of nums\n";
	eic(_)
	    -> "Not a member\n".

In fact, I'd probably do it with two tables:

	ei(Letter) -> io:format(eim(eic(Letter))).

	eic($Q) -> large;
	eic($W) -> large;
	eic($E) -> large;
	eic($R) -> large;
	eic($T) -> large;
	eic($Y) -> large;
	eic($q) -> small;
	eic($w) -> small;
	eic($e) -> small;
	eic($r) -> small;
	eic($t) -> small;
	eic($y) -> small;
	eic($0) -> digit;
	eic($1) -> digit;
	eic($2) -> digit;
	eic($3) -> digit;
	eic($4) -> digit;
	eic($5) -> digit;
	eic($6) -> digit;
	eic(_)  -> other.

	eim(large) -> "Member of capital\n";
	eim(small) -> "Member of small\n";
	eim(digit) -> "Member of nums\n";
	eim(other) -> "Not a member\n".

I know the table is large, but if you want to classify this way
here, you may well want to classify the same way somewhere else.
I like this approach a lot: it's dead simple and it's fast.

Let's look at the pure 'case' version:

	ei(A) ->
	    M = case lists:member(A, ?CAPS)
	          of true -> "Member of capital\n"
		   ; false ->
		     case lists:member(A, ?SMALL)
		       of true -> "Member of small\n"
                         ; false ->
			  case lists:member(A, ?NUMS)
			    of true -> "Member of nums"
			     ; false -> "Not a member\n"
			  end
		     end
	        end,
	    io:format(M).

Suppose the syntax were extended ever-so-slightly to
include an equivalent of Algol 68's "ouse":

	ei(A) ->
	    M = case lists:member(A, ?CAPS)
		  of true -> "Member of capital\n";
	     or case lists:member(A, ?SMALL)
		  of true -> "Member of small\n";
	     or case lists:member(A, ?NUMS)
		  of true -> "Member of nums\n"
		   ; false-> "Not a member"
		end,
	    io:format(M).

Here the sequence "; or case" is equivalent to
"; _ -> case" PLUS an extra "end" at the end.

Now do
	-define(IF, case).
	-define(THEN, of true ->).
	-define(ELIF, ; or case).
	-define(ELSE, ; false ->).
	-define(END, end).
and

	ei(A) ->
	    M = ?IF   lists:member(A, ?CAPS)  ?THEN "Member of capital\n"
		?ELIF lists:member(A, ?SMALL) ?THEN "Member of small\n"
		?ELIF lists:member(A, ?NUMS)  ?THEN "Member of nums\n"
		?ELSE                               "Not a member"
		?END,
	    io:format(M).

I'm not actually advocating the use of ?IF, ?THEN, ?ELIF, ?ELSE, ?END;
I mention them merely to clarify that the "ouse" approach gives you
something structurally similar to if-then-elif-else.
I _do_ think that something along the lines of "; or case" would be
nice, but as it stands it would be far too error-prone.

Every time something like this comes up I say the same thing:

	Show us some real code, not a toy example.

With real code, there is almost always a better way.





More information about the erlang-questions mailing list