Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -module(generators).
- -author([{name,"Fred T-H"},{email, hidden}]).
- -description("An example of generators implemented in erlang,
- allowing to generate the equivalent of lists with constant memory.").
- -vsn(0.0).
- -export([t_fib/1, y_fib/1, sum/1, fold/3, test/2, batch_test/3]).
- % macros to make the creation of generators a tad more user-friendly.
- -define(yield(X), receive {Pid, next} -> Pid ! {self(), X} end).
- -define(last_yield(X), receive {Pid, next} -> Pid ! {self(), X, done} end).
- %% Tail-recursive fibonacci function.
- t_fib(1) -> [1];
- t_fib(2) -> [1,1];
- t_fib(L) -> t_fib(3,L,[1,1]).
- t_fib(L,L,[N1,N2|_]=F) ->
- lists:reverse([N1+N2|F]);
- t_fib(C, L, [N1,N2|_]=F) ->
- t_fib(C+1,L,[N1+N2|F]).
- %% Generator-like tail-recursive fibonacci function.
- y_fib(L) ->
- y_fib(1,L,1,0).
- y_fib(L,L,N1,N2) ->
- ?last_yield(N1+N2);
- y_fib(C, L, N1,N2) ->
- N = N1+N2,
- ?yield(N),
- y_fib(C+1,L,N2,N).
- %% what the lists:sum version for generators could look like
- sum({M,Gen,Args}) ->
- Pid = spawn(M, Gen, Args),
- sum(Pid,0).
- sum(Pid,S) ->
- Pid ! {self(), next},
- receive
- {Pid, N} -> sum(Pid, S+N);
- {Pid, N, done} -> S+N
- end.
- %% ... and lists:foldl/3 (no foldr possible with generators).
- fold(F, Acc,{M,Gen,Args}) when is_function(F,2) ->
- Pid = spawn(M,Gen,Args),
- fold(F, Acc, Pid);
- fold(F, Acc, Pid) ->
- Pid ! {self(), next},
- receive
- {Pid, N} -> fold(F, F(N,Acc), Pid);
- {Pid, N, done} -> F(N,Acc)
- end.
- %% Comparing execution times of lists vs generators
- test(fold,N) ->
- erlang:statistics(wall_clock),
- F = fun(X, Acc) ->
- if X rem 2 == 0 -> Acc+1;
- true -> Acc
- end
- end,
- ?MODULE:fold(F, 0, {?MODULE, y_fib, [N]}),
- io:format("generator ok~n"),
- {_, T1} = erlang:statistics(wall_clock),
- lists:foldl(F, 0, t_fib(N)),
- io:format("list ok~n"),
- {_, T2} = erlang:statistics(wall_clock),
- if T1>0 -> {T1,T2, T2/T1};
- T2 == T1, T1 == 0 -> {T1,T2,1};
- true -> {T1,T2, '?'}
- end;
- test(sum, N) ->
- erlang:statistics(wall_clock),
- ?MODULE:sum({?MODULE, y_fib, [N]}),
- io:format("generator ok~n"),
- {_, T1} = erlang:statistics(wall_clock),
- lists:sum(t_fib(N)),
- io:format("list ok~n"),
- {_, T2} = erlang:statistics(wall_clock),
- if T1>0 -> {T1,T2, T2/T1};
- T2 == T1, T1 == 0 -> {T1,T2,1};
- true -> {T1,T2, '?'}
- end.
- %% Testing lists vs generators many times.
- batch_test(Type, N, Lim) ->
- batch_test(Type, N, 0, Lim, 0).
- batch_test(_Type,_N,Lim,Lim,Acc) ->
- Acc/Lim;
- batch_test(Type,N,Ct,Lim,Acc) ->
- {_,_,X} = test(Type,N),
- batch_test(Type,N,Ct+1,Lim,Acc+X).
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement