# Is there a better way to write these two nested loops in Erlang?

Since one month, I'm learning Erlang and I like it so much. Today, I wrote an algorithm to solve a problem. Some time ago, I used two nested for loops in C# to solve it but, solving the same problem in Erlang, I asked myself if there is a better way to write something similar to the two nested for loops I used before.

Let's say that the two nested for loops in C# are:

for(int i = 100; i<=999;i++)
{
for(int j = 100;j<=999;j++)
{
int prod = i*j;
//some logic here..
}
}


and the respective code in Erlang is the following:

loopINumber(_,LowerLim,UpperLim,Product) when LowerLim > UpperLim -> {Product};

loopINumber(ILimit,LowerLim,UpperLim,Product) ->
Product = loopJNumber(ILimit,UpperLim,LowerLim,Product),
loopINumber(ILimit,LowerLim+1,UpperLim,Product).

loopJNumber(LowerLim,UpperLim,_,Product) when LowerLim > UpperLim -> Product;

loopJNumber(LowerLim,UpperLim,ILimit,Product) ->
Product = ILimit * LowerLim,
%% some logic here..
loopJNumber(LowerLim+1,UpperLim,ILimit,Product).

start(ILimit,JLimit) -> loopINumber(ILimit,ILimit,JLimit,0).


I know that maybe there's something to improve. Being still a beginner in functional languages, most probably I'm still coding in a "sequential" or OOP way. How can I improve this Erlang code?

In general, nested for loops translate well to list comprehensions:

Prods = [I*J || I <- lists:seq(100,999), J <- lists:seq(100,999)]
// Generates a list of products to perform further logic on

• Yeah, the C# version is really bad. This is what I would write: var threeDigitNumbers = Enumerable.Range(100, 899); var palindromes = threeDigitNumbers.Zip(threeDigitNumbers, (x, y) => x * y ).Where(n => n.ToString() == new string(n.ToString().Reverse().ToArray())); This matches pretty well to your Erlang proposal. – Jörg W Mittag Jun 15 '14 at 23:56
• The hazard with list comprehensions is that you have to generate the entire list, so an arbitrarily-large number of iterations will require an arbitrarily-large amount of memory. If the problem is bounded and the size of the lists is small enough that you're comfortable with the memory consumption, this is the way to go. – Blrfl Jun 16 '14 at 4:32
• @Blrfl, most languages with list comprehensions either let you specify lazy evaluation somehow or do it by default. That lets you treat it like an arbitrarily-large, even infinite, data structure while only actually using memory for one element at a time. – Karl Bielefeldt Jun 16 '14 at 13:05
• @KarlBielefeldt: Erlang evaluates lists in full before they're used. You can do lazy evaluation in a way that looks a bit like what the OP did, but you can't do it with a list comprehension. – Blrfl Jun 16 '14 at 13:48
• @KarlBielefeldt Thank you for the answer. It seems correct and reasonable for me, I'll check that later and I'll let you know! :-) – Alberto Solano Jun 17 '14 at 7:33

To limit the problem of memory consumption with list comprehension, you can use lists:foreach/2 (note that you cannot accumulate a result with foreach/2, if necessary you can use foldl/3):

lists:foreach(
fun(X) -> lists:foreach(
fun(Y) -> io:format("~p,~p~n",[X,Y]) end,
lists:seq(1,5)) end,
lists:seq(20,25)).


or this version without prepared list, and the logic defined outside (works only since R17)

1> MyLogic = fun (init,init,init) -> []; (X,Y,R) -> [{X,Y}|R] end.
#Fun<erl_eval.18.106461118>
2> F = fun(X1,X2,Y1,Y2,Logic) ->
F1 = fun F1(X,R) when X == X2+1 -> R;
F1(X,R) -> F2 = fun F2(Y,Ry) when Y == Y2+1 -> Ry;
F2(Y,Ry) ->
%% your logic here, for example
NR = Logic(X,Y,Ry),
F2(Y+1,NR)
end,
F1(X+1,F2(Y1,R))
end,
F1(X1,Logic(init,init,init))
end.
#Fun<erl_eval.11.106461118>
3> F(1,3,21,22,MyLogic).
[{3,22},{3,21},{2,22},{2,21},{1,22},{1,21}]
4>