[erlang-questions] How to do counters?

Michael Truog <>
Tue Jun 30 05:37:43 CEST 2009


I found it interesting to abstract from Richard O'Keefe's and Witold
Baryluk's examples to create something like a python iterator/generator:

-module(counter).
-export([new/0]).

new() ->
    operation:new(fun(State) -> State + 1 end, 0).

-module(operation_impl).
-export([new/2]).

new(F, State) when is_function(F) ->
    operation:instance({operation, spawn(fun() -> loop(F, State) end)}).

loop(F, State) when is_function(F) ->
    receive {next, Sender} ->
        Sender ! {self(), State},
        loop(F, F(State))
    end.

-module(operation, [Operation]).
-export([new/2, next/0]).

new(F, State) when is_function(F) ->
    operation_impl:new(F, State).

next() ->
    ipc(Operation, next).

ipc({operation, Pid}, Msg) when is_pid(Pid) ->
    Pid ! {Msg, self()},
    receive {Pid, Result} -> Result end.


Erlang R13B01 (erts-5.7.2) [source] [64-bit] [smp:4:4] [rq:4]
[async-threads:0] [kernel-poll:false]

Eshell V5.7.2  (abort with ^G)
1> c(operation_impl).
{ok,operation_impl}
2> c(counter).
{ok,counter}
3> Itr = counter:new().
{operation,{operation,<0.45.0>}}
4> Itr:next().
0
5> Itr:next().
1
6> Itr:next().
2
7> Itr:next().
3
8> Itr:next().
4
9> Itr:next().
5




Witold Baryluk wrote:
> Dnia 2009-06-30, wto o godzinie 11:46 +1200, Richard O'Keefe pisze:
>   
>> On Jun 30, 2009, at 4:09 AM, Jarrod Roberson wrote:
>>     
>>> That doesn't "smell" right to me. Is there a better way to create
>>> "instances" of these counter module examples?
>>>       
>> Just have a counter:new() function that returns you the PID
>> of a new process.
>>
>> 	-module(counter).
>> 	-export([new/0, read/1, up/1, down/1, reset/1]).
>>
>> 	new() ->
>> 	    {counter,spawn(fun () -> loop(0) end)}.
>>
>> 	loop(N) ->
>> 	    receive {Msg,Sender} ->
>> 	        Sender ! {self(), N},
>> 	        loop(case Msg
>> 		       of read -> N
>> 		        ; up   -> N + 1
>> 		        ; down -> N - 1
>> 		        ; reset-> 0
>> 		     end)
>> 	    end.
>>
>> 	read(Counter) ->
>> 	    ipc(Counter, read).
>>
>> 	up(Counter) ->
>> 	    ipc(Counter, up).
>>
>> 	down(Counter) ->
>> 	    ipc(Counter, down).
>>
>> 	reset(Counter) ->
>> 	    ipc(Counter, reset).
>>
>> 	ipc({counter,Pid}, Msg) when is_pid(Pid) ->
>> 	    Pid ! {Msg,self()},
>> 	    receive {Pid,Result} -> Result end.
>>
>> Bind the result of a call to counter:new() to a variable,
>> and use that variable.  Example:
>>
>> 1> c(counter).
>> {ok,counter}
>> 2> C1 = counter:new().
>> {counter,<0.38.0>}
>> 3> C2 = counter:new().
>> {counter,<0.40.0>}
>> 4> counter:up(C1).
>> 0
>> 5> counter:read(C1).
>> 1
>> 6> counter:read(C2).
>> 0
>>     
> You can also use parametrized modules:
>
>
> -module(counter).
> -export([new/0]).
>
> new() ->
> 	C = {counter,spawn(fun () -> loop(0) end)},
> 	counter2:instance(Counter).
>
> loop(X) -> ...
>
>
> -module(counter, [Counter]). %% parametrized module
> -export([read/0, up/0, down/0, reset/0]).
>
> read() ->
>     ipc(Counter, read).
>
> ...
>
>
>
>
> Then just use:
>
> C1 = counter:new().
> C2 = counter:new().
> C1:up().
> C1:read().
> C2:read().
>
>
> This is just syntactic sugar.
>
>
>   



More information about the erlang-questions mailing list