[erlang-questions] style question - best way to test multiple non-guard conditions sequentially

Siraaj Khandkar siraaj@REDACTED
Thu Jun 20 01:57:37 CEST 2013


On 06/19/2013 05:50 PM, Dmitry Kolesnikov wrote:
> Hello,
>
> I am solving this problem in following way:
>
> run() ->
>     maybe_cond1(cond1(), …).
>
> maybe_cond1(false, …) ->
>     maybe_cond2(cond2(), …);
> maybe_cond1(true,  …) ->
>     % do cond1.
>
> maybe_cond2(false, …) ->
>     maybe_cond2(cond3(), …);
> maybe_cond2(true,  …) ->
>     % do cond2.
>
> maybe_cond3(false, …) ->
>     % do failure
> maybe_cond3(true,  …) ->
>     % do cond3.
>
> this approach allows you to have as many conditions as you like.
> The code can be simplified by using lists:fold and closers e.g.
>
> lists:foldl(fun assert/2, false, [fun cond1/0, fun cond2/0, fun cond3/0]).
>
> assert(_, true) ->
>     true;
> assert(Fun, false) ->
>     Fun().
>
> cond1() ->
>     case is_cond1() of
>        true ->
>           % do condition 1
>           true;
>        false ->
>           false
>     end.
>
>>
> but I do prefer the first approach.


I like the fold approach, but a bit more specialized:


     fold_until_error([], X) ->
         {ok, X};
     fold_until_error([F|Fs], X) ->
         case F(X) of
             {ok, Y}      -> fold_until_error(Fs, Y);
             {error, _}=E -> E
         end.

     do_stuff(Stuff) ->
         Conditions =
             [ fun c1/1
             , ...
             , fun cn/1
             ],
         case fold_until_error(Conditions, Stuff) of
             {ok, Data}      -> ...;
             {error, Reason} -> ...
         end.


One can, of course, use a boolean() instead of ok|error tuples, but I 
prefer it because you can know exactly what did not pass and for what 
reason [1].


[1]: http://existentialtype.wordpress.com/2011/03/15/boolean-blindness/



> On Jun 19, 2013, at 9:23 PM, Jonathan Leivent <jleivent@REDACTED> wrote:
>
>> Suppose one has multiple conditions that are not guards that need to be tested sequentially (meaning, only test condition N+1 after condition N tests false) in a function.  Using a case or if in a simplistic way would then produce considerable nesting, especially as the number of conditions increases above 2 or 3.
>>
>> Is there some way in Erlang to write such code without either breaking up the function clause or using high degrees of nesting?
>>
>> The closest I can come is something like:
>>
>> fun(...) ->
>>   C1 = cond1(...),
>>   C2 = C1 orelse cond2(...),
>>   C3 = C2 orelse cond3(...),
>>   if C1 -> ...;
>>      C2 -> ...;
>>      C3 -> ...;
>>      true -> ...
>>   end.
>>
>> Which works, but looks rather cryptic.  It also seems like it is doing all of the branching at least twice.
>>
>> I guess this also implies the question: why does Erlang require the conditions in an if statement to be guards?
>>
>> -- Jonathan



More information about the erlang-questions mailing list