[erlang-questions] first erlang program
Sat Jan 5 15:21:45 CET 2013
Le 04/01/2013 18:19, Rustom Mody a écrit :
> Wrote my first erlang program -- sieve of eratostenes;
Funny, it was also my first attempt to Erlang, starting from an Ada
example in "Concurrent and Real-Time Programming in Ada" by Alan Burns
and Andy Wellings; and we reprogrammed it (well, yet another variant) as
a group exercise during our Erlang Dojo in Paris last December... :-)
Some comments below.
> -export([main/0, gen/1, sieve/0, filtloop/2]).
Because you spawn the funs, you only need to export "main".
> -define (MAX, 200000).
> gen(Proc) -> gen(Proc,2).
> gen(Proc, N) ->
> if N =< ?MAX -> Proc ! N,
> gen(Proc, N+1);
> true -> stop
> filtloop(Prime, NS) -> % NS is NextSieve
Or rename "NS" into "Next_Sieve" :-)
And maybe refactor with two function clauses to avoid the if.
But the main issue I guess here is "stop", which should be more: send
"stop" to the first sieve (prime number 2) and have it resend "stop" the
next sieves so that they all stop. See also at the end of this email.
With your version, if you run the program from an erlang shell and then type
you'll see that all the sieve-processes are still running.
> N when is_integer(N) ->
Well, you may think again about why you would really need the guard
here. If it is just not to catch "stop", then move the "stop" clause
below to the first place.
> if N rem Prime =/= 0 ->
> NS ! N;
> true -> ok
> stop -> ok; % io:format("Stopping ~w~n", [Prime]);
Again, good idea but I don't think any "stop" message is ever sent.
> XX -> io:format("Something strange in filtloop~w~n", [XX])
Indeed. But I think you have let go with defensive programming in Erlang.
> sieve() ->
> receive Prime -> ok end,
> io:format("~w~n", [Prime]),
> Nextsieve = spawn(fun sieve/0),
> filtloop(Prime, Nextsieve).
> main() ->
> gen(spawn (fun sieve/0)).
I think the Erlang way would be to name the "main" function "start"
instead of "main". Juste because it is the default name from an erl
command perspective: see "-run" at <http://www.erlang.org/doc/man/erl.html>.
> It is modelled after this shell script (consisting of 3 scripts)
> $ cat gen.sh
> while true; do
> echo $i
> i=`expr $i + 1`
> $ cat filt.sh
> while true; do
> read x
> if [ 0 != `expr $x % $1` ] ; then
> echo $x
> $ cat sieve.sh
> read x
> echo $x
> filt.sh $x | sieve.sh
> Call like this
> gen.sh | sieve
> Performance wise its fun to watch the erlang go 10 (50?) times faster
> than the shell script
> However the shell script has an elegance that the erlang does not have
> because I dont know how to 'anonymize'
> the stdin/stdout that a classic Unix pipeline gives
> Also more basic noob questions like how to avoid the io:format
> statements etc
I think you have to put some concurrent observer pattern in place, in
order to distribute the primes to whatever clients need them ?
> TIA for any tips/guidance
Here is how I refactored your code (still io:format()), but it's not
optimal I think. I'll try to merge your version with ours, but later... :-)
-define (MAX, 200000).
gen(spawn (fun sieve/0)).
gen(Sieve) -> gen(Sieve, 2).
gen(Sieve, N) when N =< ?MAX ->
Sieve ! N,
gen(Sieve, N) ->
io:format("Stopping at ~b~n", [N]),
Sieve ! stop.
filtloop(Prime, NextSieve) ->
NextSieve ! stop,
N rem Prime =/= 0 ->
NextSieve ! N;
NextSieve = spawn(fun sieve/0),
More information about the erlang-questions