Tom coates
Tom coates

Reputation: 53

Haskell version of double loop

I need to do the following in Haskell and can't think of the correct method to do it:

for (int i=0; i<100; i++)
  for (int a=0; a<100; a++)
     foo = (i, a);

I also don't want 'duplicates' returned so there's not both (1, 50) and (50, 1). Any ideas on how to do this?

Upvotes: 0

Views: 354

Answers (4)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477686

Well first of all if you do not want duplicates, you can add the constraint i <= a. Or you can thus rewrite your code like:

for (int i=0; i<100; i++)
  for (int a=i; a<100; a++)
     foo = (i, a);

Next we can use list comprehension for this:

[(i,a) | i <- [0..99], a <- [i..99]]

So we let i iterate over 0..99 (both inclusive), and a over i..99. If we take smaller bounds (6 instead of 99) we obtain:

Prelude> [(i,a) | i <- [0..6], a <- [i..6]]
[(0,0),(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(2,2),(2,3),(2,4),(2,5),(2,6),(3,3),(3,4),(3,5),(3,6),(4,4),(4,5),(4,6),(5,5),(5,6),(6,6)]

Upvotes: 1

Aadit M Shah
Aadit M Shah

Reputation: 74244

You can use list comprehensions:

foo :: [(Int, Int)]
foo = [(i, a) | i <- [0..99], a <- [i..99]]

Note that there's no mutation in Haskell. Hence, you can't change the value of foo. That's why I made it into a list instead.

Upvotes: 7

Redu
Redu

Reputation: 26201

You may also use applicative functors and simply do like this;

Prelude> (,) <$> [0..2] <*> [0..3]
[(0,0),(0,1),(0,2),(0,3),(1,0),(1,1),(1,2),(1,3),(2,0),(2,1),(2,2),(2,3)]

Upvotes: 2

HTNW
HTNW

Reputation: 29193

If you don't want duplicates, then the loop is really:

for(int i = 0; i < 100; i++)
  for(int j = i; j < 100; j++)
    something(i, j);

Which can be made into Haskell as any of

-- raw binds
[0..99] >>= \i ->
  [i..99] >>= \j ->
    return $ something i j

-- do-notation
do i <- [0..99]
   j <- [i..99]
   return $ something i j

-- list comprehension
[ something i j | i <- [0..99], j <- [i..99]]

Upvotes: 1

Related Questions