Sometimes I miss destructively updating local variables
RCB
rcbeerman@REDACTED
Fri Jul 7 07:10:12 CEST 2006
Maybe something like this...
-record(vrec, {x1, y1, x2, y2}). % (or just use a 'raw' tuple if the
x1,.. set is static)
make_line_rec([{Tag, Ofs, Len} | T], B, Acc, V)
when Tag == x1; Tag == y1; Tag == x2; Tag == y2 ->
make_line_rec(T, B, Acc, parse_units(Tag, V, B, Ofs, Len));
make_line_rec([{Tag, _, _} = Attr|T], B, Acc, V) ->
case is_attr(Tag) of
true ->
make_line_rec(T, B, [get_attr(Attr, B)|Acc], V);
false ->
make_line_rec(T, B, Acc, V)
end
end;
make_line_rec([], _, Acc, V) ->
{line, Acc, V#vrec.x1, V#vrec.y1, V#vrec.x2, V#vrec.y2}.
parse_units(Tag, V, B, Ofs, Len) ->
% create data to assign to one of the x1... vars
set_vrec(Tag, V, Data).
set_vrec(x1, V, Data) -> V#vrec{x1 = Data};
set_vrec(x2, V, Data) -> V#vrec{x2 = Data};
...
Of course, I'm pushing some of the density down beyond parse_units,
but this seems to be what I typically do. Isolating the X1,... vars
into a single #vrec{} also makes the function a little easier to
modify if you ever need to add extra elements.
My .02....
Rich
On 7/6/06, James Hague <james.hague@REDACTED> wrote:
> Often I find myself writing a function that's just a case statement
> where each branch ends with a tail-recursive call. Here's an example
> pulled from working code:
>
> make_line_rec([{Tag,Ofs,Len}=Attr|T], B, Acc, X1, Y1, X2, Y2) ->
> case Tag of
> x1 -> make_line_rec(T, B, Acc, parse_units(B, Ofs, Len), Y1, X2, Y2);
> y1 -> make_line_rec(T, B, Acc, X1, parse_units(B, Ofs, Len), X2, Y2);
> x2 -> make_line_rec(T, B, Acc, X1, Y1, parse_units(B, Ofs, Len), Y2);
> y2 -> make_line_rec(T, B, Acc, X1, Y1, X2, parse_units(B, Ofs, Len));
> _ ->
> case is_attr(Tag) of
> true -> make_line_rec(T, B, [get_attr(Attr, B)|Acc], X1,
> Y1, X2, Y2);
> false -> make_line_rec(T, B, Acc, X1, Y1, X2, Y2)
> end
> end;
> make_line_rec([], _, Acc, X1, Y1, X2, Y2) -> {line, Acc, X1, Y1, X2, Y2}.
>
> What bugs me is having to list all the variables in the make_line_rec
> call. In reality, this function is just a while loop, and each time
> through the loop one of a set of local variables (Acc, X1, Y1, X2, Y2)
> is updated. Before any functional purists jump on me, this is EXACTLY
> how the generated BEAM code works. Those variables live in registers,
> and each make_line_rec "call" destructively updates one of those
> values, then jumps to the start of the function.
>
> In fact, I could write a language with destructive updates for locals,
> and the generated code would be fast and efficient--and perfectly
> normal--Erlang. The difference being that all the listing of
> parameters goes away, and the function is less dense and simpler to
> maintain.
>
> How do other Erlang programmers deal with this?
>
> James
>
--
Rich Beerman
Cupertino, California
mobile: 408/221-2444
fax: 408/255-7944
More information about the erlang-questions
mailing list