[erlang-questions] How to do counters?
Michael Truog
mjtruog@REDACTED
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