[erlang-questions] Versioned variable names
Mikael Pettersson
mikpe@REDACTED
Tue Jun 9 18:22:57 CEST 2009
Attila Rajmund Nohl writes:
> Hello!
>
> I think there wasn't any grumbling this month about the immutable
> local variables in Erlang, so here's real world code I've found just
> today:
>
> % Take away underscore and replace with hyphen
> MO1 = re:replace(MO, "_", "-", [{return, list}, global]),
> MO2 = toupper(MO1),
> % Replace zeros
> MO3 = re:replace(MO2, "RX0", "RXO", [{return, list}, global]),
> % Insert hyphen if missing
> MO5 = case re:run(MO3, "-", [{capture, none}]) of
> nomatch ->
> insert_hyphen(MO3);
> match ->
> MO3
> end,
>
> I think it's fairly clumsy to use MOx (MO for managed object) in the
> code. MO4 was removed during the regexp->re refactoring step. How to
> eliminate the versioned variable names? The
> MOAfterUnderscoresWereReplaced, UpperCaseMO, MOAfterRX0WasReplaced,
> etc. variablenames are really ugly. It used to use regexp, so at that
> point it wasn't possible to easily nest the whole into one call, but
> that would be still ugly. So any other ideas?
This has nothing to do with mutable variables (values or
bindings), and everything to do with Erlang's unorthodox
(for a functional language) scoping rules and semantics
for "Var = Expr".
Languages using LET for local bindings tend to allow you
to re-bind already-bound variables in nested scopes. For
instance, in Standard ML I would often write:
fun f (..) =
let state = init()
state = stage1(state)
state = finish(state)
in
... state ...
end
and similarly in Scheme using LET*.
In Erlang you can't do this, so you're stuck with:
- numbered variables (ugly but often reasonably practical)
- function composition like f(x) -> a(b(c(x))), but that
quickly gets unreadable
- using a separate function for each stage and tailcall
between the stages:
f() -> g(init()).
g(X) -> h(update(X)).
h(X) ->
NewX = if ... -> update2(X); true -> X end,
i(NewX).
i(X) ->
this doesn't entirely eliminate the variable naming problem,
but it does limit it to say two versions per function body,
which is manageable (I use this approach quite a lot in the
HiPE compiler backends when translating generic intermediate
code to architecture specific code)
- foldl (as another poster suggested), which is essentially
equivalent to function composition or using tailcalls between
per-stage functions, except it's expressed in different syntax
More information about the erlang-questions
mailing list