[erlang-questions] Re: The If expression

Anders Dahlin anders@REDACTED
Thu Apr 22 16:54:21 CEST 2010


Alt using lists:foldl/3

to_couchbeam(Fields, Values) ->
     Fun = fun ('_rev', {[undefined| Vs], Acc}) ->
                   {Vs, Acc};
               (F, {[V| Vs], Acc}) ->
                   {Vs, Acc ++ [{to_couchbeam_key(F),
                                 to_couchbeam_value(V)}]}
           end,
    {_, Res} = lists:foldl(Fun, {Values, []}, Fields),
    Res.


Alt using functions:

to_couchbeam(Fields, Values) ->
    to_couchbeam(Fields, Values, []).

to_couchbeam([], [], Acc) ->
    Acc;
to_couchbeam(['_rev'| Fields], [undefined| Values], Acc) ->
    to_couchbeam(Fields, Values, Acc);
to_couchbeam([F| Fields], [V| Values], Acc) ->
    to_couchbeam(Fields, Values,
                 Acc ++ [{to_couchbeam_key(F), to_couchbeam_value(V)}]).


Completely untested...



On 2010-04-22 16:28, James Aimonetti wrote:
> This thread is well-timed as I have an issue I wanted some help on.
> 
> I have two lists, one of keys and one of values. I want to zip them
> together, but I have one specific key/value combo that I want to exclude
> from the zipped list. For context, this is creating an appropriate
> {proplist} for couchbeam.
> 
> to_couchbeam(Fields, Values) ->
>  { lists:flatten( lists:zipwith(fun to_couchbeam_zipper/2, Fields,
> Values) ) }.
> 
> to_couchbeam_zipper(F, V) ->
>  K = to_couchbeam_key(F),
>  Val = to_couchbeam_value(V),
>  case Key == <<"_rev">> andalso Val == undefined of
>    true -> [];
>    false -> {K, Val}
>  end.
> 
> to_couchbeam_* converts various terms to formats suitable for couchbeam
> to save the document. I only want to remove the '_rev' key when it's
> value is undefined, otherwise couchbeam fails to save the document. If
> '_rev' has a defined value, great, keep it in the generated proplist.
> 
> I refactored according to some of the advice earlier, so now
> to_couchbeam_zipper is
> 
> to_couchbeam_zipper('_rev', undefined) -> [];
> to_couchbeam_zipper(F, V) -> { to_couchbeam_key(F),
> to_couchbeam_value(V) }.
> 
> So I may have answered my own question here, as concerns the case
> statement. Is there a cleaner way to zip two lists in this fashion
> without resorting to inserting an empty list for unwanted k/v pairs and
> flattening the resulting proplist?
> 
> Thanks,
> 
> James
> 
> Jay Nelson wrote:
>> Henning Deidrich offered one-armed ifs to rewrite:
>>
>> I never use the if statement.  It doesn't even occur to me to use it,
>> although writing Java or something else I use it all the time
>> naturally.  Here's the style I would use for some of your cases (some
>> of the others may not have enough context to be good examples for
>> rewriting):
>>
>> > (2)
>> >        verbose_echo(Verbose, Format, Para) ->
>> >
>> >            % Don't print if verbosity is off (false).
>> >         >>> if Verbose -> echo(Format, Para); true -> nil end.
>>
>> verbose_echo(true, Format, Para) ->
>>     echo(Format, Para);
>> verbose_echo(_, _Format, _Para) ->
>>     nil.
>>
>> It doesn't do what the comment says, and you have to consider whether
>> nil is the value you want back.  It depends on what echo/2 returns as
>> to what is appropriate (and whether the caller even cares about the
>> return value).  With this approach it is easier to test and easier to
>> add new cases (verbosity levels) or change the existing one.
>>
>>
>> >    (3)
>> >            % If exists, drop old before adding new element
>> >            Prev = gl:get(suite, Suite),
>> >         >>>    if Prev /= undefined -> gl:drop(suite, Suite); true ->
>> >        nil end,
>> >            gl:add(suite, Suite),
>>
>> Prev = case gl:get(suite, Suite) ->
>>     undefined -> nil;
>>     Defined -> gl:drop(suite, Suite), Defined
>> end,
>> gl:add(suite, Suite),
>>
>>
>> Here I made the assumption that you needed the value of Prev later. 
>> If you don't, you can drop it out and not care what the return value
>> of the case statement is.
>>
>> This is actually a common code smell to watch for.  You are setting a
>> variable, then testing for a negative value using /= constant. 
>> Instead, use case and make the first clause the constant you want to
>> exclude, everything else will match the catch-all clause.
>>
>> Even when I have case ... of true -> ...; false -> ... end   I find it
>> more comforting in erlang to know I covered the cases I care about. 
>> You can even use a single armed case if you want a freak value to
>> crash your process.
>>
>> > (5)
>> >      safe_unregister(Name) ->
>> >      Registered = whereis(Name) /= undefined,
>> >       >>> if Registered -> unregister(Name); true -> nil end.
>>
>> safe_unregister(Name) ->
>>   case whereis(Name) of
>>     undefined -> ok;
>>     Other -> unregister(Name), ok
>>   end.
>>
>> Another instance of #3.  You can easily fix the return values to
>> different ones, or have a return value after the case ... end.  If you
>> need to know the value of whereis, you can modify it to this:
>>
>> safe_unregister(Name) ->
>>    Loc = case whereis(Name) of
>>        undefined -> undefined;
>>        Other -> unregister(Name), Other
>>    end,
>>    ... computations involving Loc ...
>>   %% or even return it...
>>   Loc.
>>
>>
>> Any time you find yourself binding a variable, and then soon after
>> wanting to modify it or do an if based on a small set of values, stop,
>> back up and try using a case statement.  It has the advantage of
>> giving you multiple variables with delayed binding of the correct one
>> as your chosen value:
>>
>> Chosen = case multi_var_fun() of
>>           Val1 -> Val1;
>>           Val2 -> f(Val2);
>>           Val3 when Val3 > 0, Val3 < 5 -> g(Val3);
>>           Other -> h(Other)
>> end,
>>
>> Here Chosen is a late-bound variable with several values visited as
>> intermediate bindings before arriving at a final choice.  An
>> imperative programmer tries to do something like:
>>
>> Chosen = multi_var_fun(),
>> if (Chosen == Val1) ...
>> else ...
>>
>> The erlang way is to avoid binding the variable you care about until
>> you are absolutely sure you have the _value_ you care about, rather
>> than modifying the value along the way.   A one-armed if is
>> semantically like saying I want Val1 most of the time, and in a few
>> cases I want to change it to a different value.
>>
>> jay
>>
>>
>> ________________________________________________________________
>> erlang-questions (at) erlang.org mailing list.
>> See http://www.erlang.org/faq.html
>> To unsubscribe; mailto:erlang-questions-unsubscribe@REDACTED
>>
>>
> 
> 


More information about the erlang-questions mailing list