0

Is there an equivalent expression for the increment/decrement operator e.g. counter++? I also wonder how to properly do this?

-module(whileloop).
-export([call/0, while_loop/2]).

call() ->
    while_loop(10,0).

while_loop(Var,Counter) ->  
    case Var =:= Counter of
        false ->
            Counter += 1,
            whileloop(Var);
    end.

edit:

 -module(whileloop).
-export([call/0, while_loop/2]).

call() ->
    while_loop(10,0).

while_loop(Var, Counter) -> 
    case Var =:= Counter of
        false ->            
            while_loop(Var,Counter + 1)
    end.
pandoragami
  • 5,387
  • 15
  • 68
  • 116

3 Answers3

3

The meaning of C += 1 is to modify the value of C. It is a non sense in Erlang since it can only give the following result:

1> C = C+1.
* 1: variable 'C' is unbound
C = 1.
1
3> C = C+1.
** exception error: no match of right hand side value 2

Keep in mind that "A = B" does not mean assigns the value of B to A, but "pattern match" A against B,

  • if A is unbound then it will bind to A the value of B;
  • if A =:= B nothing is done, the process continue;
  • if A =/= B then the process crashes.

So yes, if you want to have a counter, or any information that change, you must use a state variable which is passed as argument of a recursive loop. From this point of view, your last code is correct, but lets follow what happens when you call "call()" in the shell.

first it calls, in the same process - the shell - the function while_loop(10,0).

10 is not equal to 0 so it calls immediately while_loop(10,1).

10 is not equal to 1 so it calls immediately while_loop(10,2).

and so on until it calls while_loop(10,10). Now 10 =:= 10 is true, and this result does not match any clause of the case, so you get an error and the process crash.

As your code does not contain any message receive and simply loop an loop until it crashes, thhe wole process takes only a few micro seconds, so it looks like it fails immediately.

Depending on what you expect, you can imagine several types of counter, here are 2 examples:

-module(counter).

-compile(export_all).

% one counter that help you to count some events

% interface

start_c1(End) when is_integer(End) ->
    spawn(?MODULE,counter1,[End]).

start_link_c1(End) when is_integer(End) ->
    spawn_link(?MODULE,counter1,[End]).

inc_c1(Pid) when is_pid(Pid) ->
    Ref = make_ref(),
    Pid ! {inc,self(),Ref},
    receive
        {Ref,done} -> done;
        {Ref,V} -> V
    after 1000 ->
        {error,no_response}
    end.

value_c1(Pid) when is_pid(Pid)  ->
    Ref = make_ref(),
    Pid ! {get_value,self(),Ref},
    receive
        {Ref,V} -> V
    after 1000 ->
        {error,no_response}
    end.

stop_c1(Pid)  when is_pid(Pid) ->
    Pid ! stop.

% the counter

counter1(End) -> counter1_loop(End,0).

counter1_loop(End,V) ->
    receive
        {inc,Pid,Ref} when V =/= done -> 
            NewV = case V+1 of
                End -> done;
                Nv -> Nv
            end,
            Pid ! {Ref,NewV},
            counter1_loop(End,NewV);
        {inc,Pid,Ref} ->
            Pid ! {Ref,done},
            counter1_loop(End,done);         
        {get_value,Pid,Ref} ->
            Pid ! {Ref,V},
            counter1_loop(End,V);
        stop ->
            ok
    end.

% One kind of timeout that execute something after a while - 
% note it exists a similar one in the library

start_after(T,M,F,A) when is_integer(T), is_list(A) ->
    Ref = make_ref(),
    {Ref,spawn(?MODULE,after_receive,[T,M,F,A,self(),Ref])}.

cancel_after(P) when is_pid(P) ->
    P ! cancel.


% the counter
after_receive(T,M,F,A,Pid,Ref) ->
    receive
        {cancel,Ref} -> Pid ! {after_receive,Ref,cancelled}
    after T ->
        Pid ! {after_receive,Ref,done},
        apply(M,F,A)
    end.

and here how to use them:

1> c("../src/counter").
{ok,counter}
2> {Ref,P} = counter:start_after(5000,io,format,["This is the end!" ]).
{#Ref<0.0.0.29>,<0.33.0>}
This is the end!3> 
3> {Refa,Pa} = counter:start_after(50000,io,format,["This is the end!" ]).
{#Ref<0.0.0.34>,<0.35.0>}
4> Pa ! {cancel,Refa}.
{cancel,#Ref<0.0.0.34>}
5> flush().
Shell got {after_receive,#Ref<0.0.0.29>,done}
Shell got {after_receive,#Ref<0.0.0.34>,cancelled}
ok
6> P1 = counter:start_c1(5).
<0.52.0>
7> counter:inc_c1(P1).
1
8> counter:inc_c1(P). 
{error,no_response}
9> counter:inc_c1(P1).
2
10> counter:inc_c1(P1).
3
11> counter:value_c1(P1).
3
12> counter:inc_c1(P1).  
4
13> counter:inc_c1(P1).
done
14> counter:value_c1(P1).
done
15> counter:inc_c1(P1).  
done
16> counter:stop_c1(P1).
stop
17> counter:inc_c1(P1). 
{error,no_response}
18> 
Pascal
  • 13,977
  • 2
  • 24
  • 32
1

Just recursively call while_loop with the Counter argument incremented by one:

while_loop(Var, Counter + 1)
Jorge Israel Peña
  • 36,800
  • 16
  • 93
  • 123
  • Ok but what about the equivalence of `counter++` just in case I need to know this somewhere else. – pandoragami Mar 15 '13 at 00:19
  • I tried `while_loop(Var, Counter + 1)` in the above code and its an illegal pattern? I delete the line `Counter += 1,`. – pandoragami Mar 15 '13 at 00:21
  • @lost_with_coding there isn't one in Erlang. You cant change the value of variables like that in Erlang. Read this for more information: http://stackoverflow.com/questions/9753080/is-erlang-single-assignment-different-from-haskell-immutable-values – Jorge Israel Peña Mar 15 '13 at 00:21
  • You did keep the semicolon `;` after it? And remove the `Counter += 1` line? – Jorge Israel Peña Mar 15 '13 at 00:24
1

Your edited version doesn't have a clause when Var =:= Counter and thus crashes. And you'd better use pattern matching in function clauses.

-module(whileloop).
-export([call/0, while_loop/2]).

call() ->
    while_loop(10,0).

while_loop(Var, Var) ->
    ok;
while_loop(Var, Counter) -> 
    while_loop(Var, Counter + 1).

And of course you'd need to do something inside the loop. You can use lambdas for that:

-module(whileloop).
-export([call/0, while_loop/3]).

call() ->
    while_loop(10, 0, fun(Counter) -> io:format("Counter: ~p~n", [Counter]) end).

while_loop(Var, Var, _) ->
    ok;
while_loop(Var, Counter, Fun) ->
    Fun(Counter),
    while_loop(Var, Counter + 1, Fun).
pottu
  • 332
  • 3
  • 11
Dmitry Belyaev
  • 2,573
  • 12
  • 17