Axet_small Alexey Kuzne... 3 posts

At end of 2.6 you can read bullet:

At this point you might be wondering how it’s possible to program with-
> out variables. How can you express something like X = X + 1 in Erlang?
> The answer is easy. Invent a new variable whose name hasn’t been used
> before (say X1), and write X1 = X + 1.

But my question is how it work for in for/next cycles. And IMHO right explanation is: recursion examples.

 
Alain_o_dea_small Alain O'Dea 35 posts

I think Joe was trying to get at a different kind of resetting of a variable. Think of Java.

String street = "1 Infinite Loop";
street = street.replace("1", "1A");

Erlang’s variables are a lot like Java finals:

final String street = "1 Infinite Loop";
final String correctedStreet = street.replace("1", "1A");

In Erlang:

Street = "1 Infinite Loop",
{ok, CorrectedStreet, _} = regexp:sub(Street, "1", "1A").

The ”=” operator in Erlang is not assignment although it may appear to be. It declares a constraint. It declares that the left hand and right hand sides are equal. By necessity everything on the right-hand side must be bound or set while the left-hand side may have unbound variables which will become bound to satisfy the constraint as declared.

 
Axet_small Alexey Kuzne... 3 posts

I agree. And i see that style is a good style. But really i try to imagine situation that can totally brake that logic – loops. If you try use loops in any languages you must reuse loop iterator all time. And that is a question – how to solve that. There Joe explain new style, but don’t explain main differents between languages.

 
3_small_small Joe Armstrong 7 posts

Good question !

Erlang has no loops or for/next cycles so the problem does not occur.

Basically you cannot say X = X + 1, you have to invent a new variable X1 and make sure that X1 goes “out of scope”.

So the old code (in an imperative language)

foo(X) {
    X = X + 1,
    Y = bar(X),
    ho(X, Y),
    joe(Y).
}

becomes

foo(X) -> 
    X1 = X + 1,
    Y = bar(X1),
    ho(X1, Y),
    %% At this point X1 is no longer referred to so the space for X1 can  be freed
    joe(Y).

We now call joe(Y) but where does joe(Y) return to? – to the end of foo(X) where it finds a return instruction
ultimately joe(Y) returns to the place that called foo(X) – the point is that Y is never refereed to again
in the body of foo(X) and can be garbage collected.

So we create new variables X1, X2, X3, .... and the space for these can be reclaimed
when the program can no longer access these variables.

To get the effect of a loop we write a tail-recursive recursive function. So to sum the integers from 1 to N
we might write.

sum(N) -> sum(N, 0).

sum(0, Sum) -> Sum;
sum(N, Sum) -> Sum1 = Sum + 1, %% create a new value of Sum N1 = N – 1, %% and a new value of N sum(N1, Sum1). %% call sum (again)

The last line (which calls sum) merely jumps to the start of the sum routine. Although this is a call
the system does not return to site of the call, since this merely returns immediately, instead it returns,
(this is called “last-call” optimization). Having jumped to the start of sum the variables
N1 and Sum1 are out of scope and can never be accessed again, so they get garbaged. The Erlang compiler
recognises things like this and attempts to save space by storing N1 in the register used for N (if this
is possible).

This above code is a loop (after compilation)

BTW We’d really write the second clause of sum as:

sum(N, Sum) -> sum(N-1, Sum+N)

Without the temporary variables. The version I wrote was so you can see what happens to the variables.

Hope that helps!

/Joe

 
Alain_o_dea_small Alain O'Dea 35 posts

Iterative or repeating algorithms are fairly easy to port from an imperative language (like Java) to Erlang.

For example, you want to gather some interesting property from a set of items.

In Java you would use a for loop and an accessor method:

void process(List list) {
    List output = new ArrayList();
    for (Item item : list) {
        output.add(item.getInterestingProperty());
    }
    return output;
}

In Erlang you would fold the list and extract the property with pattern matching:

process(List) ->
    lists:foldl(fun process/2, [], List).

process(#item{interestingProperty=InterestingProperty}, Output) ->
    [InterestingProperty|Output].

5 posts, 3 voices