Project Euler has a bunch of interesting mathematical programming challenges. I think they’re great for helping to learn a new language, and so will be using a few of the Euler problems to help me learn Erlang.

Here is the first problem.

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these is 23. Find the sum of all the multiples of 3 or 5 below 1000.

The problem is trivial, but it is ok to start easy. Here are three solutions; the third exploits Erlang message passing.

The first solution:

-module(p1).
-export([start/1]).

 qualifies(N) ->
     (N rem 3 == 0) or (N rem 5 == 0).

 start() ->
     Ans = lists:sum( lists:filter(fun qualifies/1, lists:seq(1,999))),
     io:format("answer is ~p~n", [Ans]).

The second solution is similar, but syntactically more elegant. Use K=999.

-module(p1a).
-export([start/1]).
start(K) ->
    Answer = lists:sum([ X || X <- lists:seq(1,K),  (X rem 3 == 0) or (X rem 5 == 0) ]),
    io:format("answer is ~p~n", [Answer]).

These two solutions are essentially the same. Out of curiousity, I ran the code for larger runs of integers. Both were ok for the ints 1…1000000 but choked when I went up to 10,000,000. The problem is the allocation of a list of 10,000,000 elements exhausted ram (other stuff was running). The third solution avoids the use of a huge list (all you Haskell guys are free to smirk and go on about lazy evaluation).

I made the solution a bit more general than the problem called for.

-module(ator1).
-export([start/1, genseq/1, genseq/2, genseq/3, accumulate/0, accumulate/1,  accumulate/2]).

%% generate ints from 1 to N, inclusive
genseq(N) ->
    genseq(1, N, 1).

%% generate ints K ... N
genseq(K, N) ->
    genseq(K, N, 1).

%% generate ints from K, K+Delta, ... with upper bound N
genseq(K, N, Delta) ->
    receive
	{Pid, _} ->
	    if
	        K < N ->
		    Pid ! {self(), K},
		    genseq(K+Delta, N, Delta);
		K == N ->
		    Pid ! {self(), K},
		    Pid ! {self(), done};
		K > N ->
		    Pid ! {self(), done}
	    end
     end.

ident(N) -> N.

filter(N) when (N rem 3== 0) ->N;
filter(N) when (N rem 5 == 0) ->N;
filter(_) ->0.

accumulate() ->
    accumulate(0).

accumulate(Total) ->
    accumulate(Total, fun ident/1).

accumulate(Total, Filter) ->
    receive
	{Pid, done} ->
	    io:format("total = ~p~n", [Total]);
	{Pid, N} ->
	    Pid ! {self(), next},
	    accumulate(Total + Filter(N), Filter)
    end.

start(N) ->
    Seq = spawn(ator1, genseq, [N]),
    Accumulate = spawn(ator1, accumulate, [0, fun filter/1]),
    Seq ! {Accumulate, next}.