Take the 2-minute tour ×

I'm new to Erlang and pretty new to functional programming in general.

I've been having a really good time with Erlang so far (even though Erlang's punctuation has had me trip up a few times ;)), but I'd really love it if I could get some feedback on my code from more experienced Erlang programmers.

My code seems to work alright, but I'm sure you guys could offer a lot of advice for improvement! :)

Here's a program to solve the 2nd Project Euler problem (find the sum of all even primes below four million), split up into two modules:

-export([takewhile/2, take/2]).

%% Recursively pick elements from a lazy sequence while Pred(H) is true
takewhile(Pred, [H|T]) ->
   case Pred(H) of
       true -> [H|takewhile(Pred, T())];
       false -> []

%% Take a certain number of elements from a lazy sequence
%% A non-tail recursive version
take(0, _) -> [];
take(Number, [H|T]) ->
   [H|take(Number - 1, T())].

The second module solves the actual problem:

-import(seqs, [takewhile/2]).
-export([lazyfib/0, solve/0]).

%% Sums the numbers in a list (for practice's sake)
sum([]) -> 0;

%% Practicing some list comprehensions as well!
filter(P, Xs) -> [ X || X <- Xs, P(X) ].

%% Lazy sequence that generates fibonacci numbers
lazyfib(A, B) -> [A | fun () -> lazyfib(B, A + B) end].
lazyfib() -> lazyfib(0, 1).

%% Generate all fibonacci terms that are less than 4 million and sum the
%% even terms
solve() ->
   Fibs = seqs:takewhile(fun (X) -> X < 4000000 end, lazyfib()),
   sum(filter(fun (X) -> X rem 2 =:= 0 end, Fibs)).

Thanks in advance, and please tell me if this is not the appropriate forum for this kind of question! :)

share|improve this question
Is your takewhile function really any different from lists:takewhile/2? Also your take function seems similar to lists:sublist/2. Someone can probably correct me on this, but I don't think your "seqs" functions are really lazy in the sense that e.g. Haskell uses laziness. Erlang doesn't have infinite lists for instance. –  Magnus Kronqvist Mar 31 '11 at 11:33
add comment

3 Answers

up vote 1 down vote accepted

Here's a general tip. You should try to use tail recursion when possible (again, for practice's sake).

For example, this function is not tail recursive:

sum([]) -> 0;

because the result of sum(T) has to be returned so that it can be added to H. Each recursive call adds to a callstack. You will run out of memory or crash if your list is too big, like when summing many primes.

To make the function tail recursive, use an accumulator like this:

%% Hide the use of the accumulator, so caller can still use sum/1.
%% Also note the period ending this function definition.
sum([], Acc) -> Acc;
sum([H|T], Acc) -> sum(T, H + Acc).

While this looks similar, notice that the addition is done before the recursive call, which ends up being the last instruction. That means the compiler can optimize it as a jump instead of a call (since it never has to come back to this function), so you don't create an enormous callstack.

Also be careful of the punctuation when going from sum/1 to sum/2. The functions with different arity are different, even if they have the same name. That is why the first line ends with a period instead of a semi-colon.

Hope that helps. Good luck.

share|improve this answer
Thanks! :) I've been trying to solve subsequent problems using tail recursion. The punctuation in Erlang got me really bad a couple of times, but I'm getting used to it now. I discovered that the punctuation does have its upsides as well - it allows the Erlang mode for Emacs behave really intelligently, for one :) –  Christoffer Mar 31 '11 at 9:20
add comment

I understand beauty of generalized functional approach with iterators and generators but anyway straightforward solution is far simpler and nice:



euler2(Limit) -> euler2(Limit, 0, 1, 1).

euler2(Limit, Sum, A, _B) when A > Limit -> Sum;
euler2(Limit, Sum, A, B) ->
  NewSum = case A rem 2 of 0 -> Sum+A; _ -> Sum end,
  euler2(Limit, NewSum, B, A+B).
share|improve this answer
add comment

Considering running your code through Tidier.


I saw a short presentation on it, and some of the code style and LOC optimizations it made were simply astounding.

share|improve this answer
That's a pretty nice tool! I tried it with my latest file and while it didn't change any code it sure made it prettier! ;) (I would upvote your answers but I don't have the rep yet :P) –  Christoffer Mar 31 '11 at 9:26
add comment

Your Answer


