[erlang-questions] Reassigning variables

mats cronqvist <>
Thu Mar 19 13:22:31 CET 2009


Matthew Dempsky <> writes:

> Here's an actual block of code from the Erlang compiler:
>
>     lc_tq(Line, E, [{generate,Lg,P,G}|Qs0], Mc, St0) ->
>         {Gs,Qs1} =  splitwith(fun is_guard_test/1, Qs0),
>         {Name,St1} = new_fun_name("lc", St0),
>         {Head,St2} = new_var(St1),
>         {Tname,St3} = new_var_name(St2),
>         LA = lineno_anno(Line, St2),
>         LAnno = #a{anno=LA},
>         Tail = #c_var{anno=LA,name=Tname},
>         {Arg,St4} = new_var(St3),
>         {Nc,[],St5} = expr({call,Lg,{atom,Lg,Name},[{var,Lg,Tname}]}, St4),
>         {Guardc,St6} = lc_guard_tests(Gs, St5),     %These are always flat!
>         {Lc,Lps,St7} = lc_tq(Line, E, Qs1, Nc, St6),
>         {Pc,St8} = list_gen_pattern(P, Line, St7),
>         {Gc,Gps,St9} = safe(G, St8),                %Will be a
> function argument!
>         Fc = function_clause([Arg], LA, {Name,1}),
>         ....

  how about this then.

my_expr(Lg,Name,Tname,St) ->
  expr({call,Lg,{atom,Lg,Name},[{var,Lg,Tname}]},St).

my_lanno(Line,Tname,St) ->
  LA = lineno_anno(Line,St),              
  {LA,#a{anno=LA},#c_var{anno=LA,name=Tname}}.

my_lc_tq(Line, E, [{generate,Lg,P,G}|Qs], Mc, St) ->
  all(s(qs,st,{Qs,St}),
       [fun(X)->s(X,gs,qs1,       splitwith(fun is_guard_test/1,f(X,qs)))end
       ,fun(X)->s(X,name,st,      new_fun_name("lc", f(X,St)))end
       ,fun(X)->s(X,head,st,      new_var(f(X,st)))end
       ,fun(X)->s(X,tname,st,     new_var_name(f(X,st)))end
       ,fun(X)->s(X,la,lanno,tail,my_lanno(Line,f(X,tname),f(X,st)))end
       ,fun(X)->s(X,arg,st,       new_var(f(X,st)))end
       ,fun(X)->s(X,nc,'',st,     my_expr(Lg,f(X,name),f(X,tname),f(X,st)))end
       ,fun(X)->s(X,guardc,st,    lc_guard_tests(f(X,gs),f(X,st)))end
       ,fun(X)->s(X,lc,lps,st,    lc_tq(Line,E,f(X,qs),f(X,nc),f(X,st)))end
       ,fun(X)->s(X,pc,st,        list_gen_pattern(P,Line,f(X,st)))end
       ,fun(X)->s(X,gc,gps,st,    safe(G,f(X,st)))end
       ,fun(X)->s(X,fc,function_clause([f(X,arg)],f(X,la),{f(X,name),1}))end]).

  slightly longer (15 vs. 19 lines) and it needs the (trivial) helper
  functions s(tore), f(etch) and all. But a heck of a lot easier to
  maintain and extend(*).

  I guess you could turn the fun(X)->s(X,...)end boilerplate into a
  macro(**), but I'm not sure that actually improves things.

  mats

(*) At least I think so. Of course, I also think the original is an
abomination. Shows what I know.

(**) like this;

-define(S(X,Ts,Xp), fun(X)->s(X,Ts,Xp)end).

my_lc_tq(Line, E, [{generate,Lg,P,G}|Qs], Mc, St) ->
  all(s(qs,st,{Qs,St}),
       [?S(X,{gs,qs1},     splitwith(fun is_guard_test/1,f(X,qs)))
       ,?S(X,{name,st},    new_fun_name("lc", f(X,St)))
       ,?S(X,{head,st},    new_var(f(X,st)))
       ,?S(X,{tname,st},   new_var_name(f(X,st)))
       ,?S(X,{la,lan,tail},my_lanno(Line,f(X,tname),f(X,st)))
       ,?S(X,{arg,st},     new_var(f(X,st)))
       ,?S(X,{nc,'',st},   my_expr(Lg,f(X,name),f(X,tname),f(X,st)))
       ,?S(X,{guardc,st},  lc_guard_tests(f(X,gs),f(X,st)))
       ,?S(X,{lc,lps,st},  lc_tq(Line,E,f(X,qs),f(X,nc),f(X,st)))
       ,?S(X,{pc,st},      list_gen_pattern(P,Line,f(X,st)))
       ,?S(X,{gc,gps,st},  safe(G,f(X,st)))
       ,?S(X,{fc},         function_clause([f(X,arg)],f(X,la),{f(X,name),1}))]).



More information about the erlang-questions mailing list