### Erlang fizzbuzzery: Project Euler Problem 1

Another excercise in solving a simple problem using multiple programming idioms in the same language, Erlang. This time the simple problem is Problem 1 from Project Euler: "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 multiples is 23. Find the sum of all the multiples of 3 or 5 below 1000." In particular, the solutions presented are (1) a simple single-function loop which uses `if`

to check for termination and matching numbers, (2) a simple loop using Erlang's *guard* syntax, and (3) a few solutions using some of the functions of the `lists`

module, one using Erlang's *list comprehension* syntax.

Simple loop without guards:

-module(euler_1_loop). -export([start/0,solve_euler_1/1]). start() -> io:format("~w~n",[solve_euler_1(1000)]). solve_euler_1(N) -> solve_euler_1(0,1,N). solve_euler_1(Sum,Cur,N) -> if Cur >= N -> Sum; (0 == (Cur rem 3)) or (0 == (Cur rem 5)) -> solve_euler_1(Sum+Cur,Cur+1,N); true -> solve_euler_1(Sum,Cur+1,N) end.The above does a few things right, such as remembering that all calls in Erlang are

*call by value*and thus the easiest way to implement a recursive loop for this little problem is by simply keeping all the relevant data around as function parameters. It uses Erlang's

`if`

to test a series of expressions. As before, the simple module is constructed so that its main path, `solve_euler_1/1`

, is exported so it can be externally tested, and the simple `start`

function is exported so we can simply run the example (after compiling with `erlc`

, of course) with: erl -s euler_1_loop -run init stop -noshellWe can use Erlang's guard syntax to transform the above code into:

-module(euler_1_guards). -export([start/0,solve_euler_1/1]). start() -> io:format("~w~n",[solve_euler_1(1000)]). solve_euler_1(N) -> solve_euler_1(0,1,N). solve_euler_1(Sum,Cur,N) when Cur >= N -> Sum; solve_euler_1(Sum,Cur,N) when (0 == (Cur rem 3)) or (0 == (Cur rem 5)) -> solve_euler_1(Sum+Cur,Cur+1,N); solve_euler_1(Sum,Cur,N) -> solve_euler_1(Sum,Cur+1,N).The above is a fairly simplistic example, but after all the problem is itself fairly simplistic. The first match for

`solve_euler_1/3`

checks the end case, for when we have reached the end of the list of numbers we are supposed to be adding, and simply returns our running total. The second match checks to see if the current number is evenly divisible by 3 or 5, and if so, adds the current number to the running total, adds one to the current number, and re-enters the loop, keeping in mind that the matching process will start over again and so the end case will be handled appropriately. The last match simply leaves the running total alone, adds one to the current number, and re-enters the loop.Using the

`lists`

module and Erlang's *list comprehension*syntax:

-module(euler_1_comprehension). -export([start/0,solve_euler_1/1]). start() -> io:format("~w~n",[solve_euler_1(1000)]). solve_euler_1(N) -> lists:sum([X || X <- lists:seq(1,N-1), (X rem 3 == 0) or (X rem 5 == 0)]).The above illustrates four important concepts:

`lists:sum(List)`

which returns the sum of each element in a list;`lists:seq(Start,End)`

which returns a list of numbers from `Start`

through `End`

;`[X || X <- List]`

which is a simple list comprehension syntax example that actually produces the exact same input `List`

(unlike `[math:pow(X,2) || X <- List]`

which produces a list of the squares of the elements in the input `List`

, or `[{n,X} || X <- List]`

which produces a list of tuples where the first element is the atom 'n' and the second element is the original list element, or `[{X,math:pow(X,2)} || X <- List]`

, or...);`[X || X <- List, Expression]`

which *filters*the original

`List`

by only including those elements for which the given `Expression`

is true, in this case, `(X rem 3 == 0) or (X rem 5 == 0)`

.Similar to the above is using the

`lists`

module's `filter`

function: -module(euler_1_filter). -export([start/0,solve_euler_1/1]). start() -> io:format("~w~n",[solve_euler_1(1000)]). solve_euler_1(N) -> lists:sum(lists:filter(fun(X) -> (X rem 3 == 0) or (X rem 5 == 0) end,lists:seq(1,N-1))).This introduces the

`filter`

function itself, as well as the creation of an *anonymous*function in Erlang.

Yet another method of solving this problem comes again from the

`lists`

module, this time using `foldl`

to accumulate along the list, and showing that anywhere you might declare an anonymous function (such as above) you can also use named functions: -module(euler_1_foldl). -export([start/0,solve_euler_1/1]). start() -> io:format("~w~n",[solve_euler_1(1000)]). solve_euler_1(N) -> lists:foldl(fun accum_fun/2,0,lists:seq(1,N-1)). accum_fun(X,Sum) when X rem 3 == 0; X rem 5 == 0 -> X + Sum; accum_fun(_X,Sum) -> Sum.Here we have a couple of new things to see, of course the

`foldl`

function itself, but also we use a named function, `accum_fun`

, where previously we had declared an anonymous function inline, and we used a special guard syntax where `;`

is really quite the same as `or`

.Hopefully this was at least a little helpful in illustrating a few ways that using some of Erlang's features can be fun, simple, fast, and clear. This example didn't really give us an opportunity to look at processes or matching, but I'm sure those will come along again soon enough.

## No comments:

Post a Comment