Organize the sequence of tuple in a Haskell List comprehension

Viewed 149

Hello dear Community,

I'm trying organize the sequence of tuple in a Haskell List comprehension.

e.g. I got the following List Comprehension:

[ (a,b,c,d) | a <- [0, 50, 100, 150, 200]
            , b <- ['a', 'b', 'c']
            , c <- [True, False]
            , d <- ['A', 'B']
            ]

and get:

[ (0, 'a', True, 'A'), (0, 'a', True, 'B'), (0, 'a', False, 'A')
, (0, 'a', False, 'B'), (0, 'b', True, 'A'), (0, 'b', True, 'B')
, (0, 'b', False, 'A'), (0, 'b', False, 'B'), (0, 'c', True, 'A')
,(0, 'c', True, 'B'), (0, 'c', False, 'A')..

Now I want the sequence like following:

[ (0, 'a', True, 'A'), (0, 'a', True, 'B'), (0, 'b', True, 'A')
, (0, 'b', True, 'B'), (0, 'c' ,True, 'A'), (0, 'c', True, 'B')
, (0, 'a', False, 'A'), (0, 'a', False, 'B')..

That means: First a trade off between the capital letters 'A' & 'B', then a trade off between the small letters 'a','b','c', as a penultimate the trade off between the boolean values True, False and finaly the numbers.

Unfortunately I have absolutely no idea how to realize these and i want to know how you can manipulate the sequence of a list with tuple [(a,b,c)].

1 Answers

The order of the x <- list statements in list comprehension is important. If you write:

[expr | x <- list1, y <- list2]

this is equivalent to a nested for loop with y being the inner loop. So a Python equivalent with loops would be:

for x in list1:
    for y in list2:
        expr

and thus the inner loop is entirely exhausted before the outer loop picks the next value.

So we need to reorder the statements such that we first pick d, then b, then c and finally a. So that means that we turn:

[(a,b,c,d)| a <- [0,50..200], b <- "abc", c <- [True,False], d <-"AB"]

(I made the lists shorter in notation)

into:

-- [(a,b,c,d)| a <- [0,50..200], b <- "abc", c <- [True,False], d <-"AB"]
--             |                  \_________/_____              |
--             |                   ________/      \             |
--             |                  /                \            |
   [(a,b,c,d)| a <- [0,50..200], c <- [True,False], b <- "abc", d <- "AB"]

(the comment is only to visualize the difference)

which generates:

Prelude> [(a,b,c,d)| a <- [0,50..200], c <- [True,False], b <- "abc", d <- "AB"]
[(0,'a',True,'A'),
 (0,'a',True,'B'),
 (0,'b',True,'A'),
 (0,'b',True,'B'),
 (0,'c',True,'A'),
 (0,'c',True,'B'),
 (0,'a',False,'A'),
 (0,'a',False,'B'),
 (0,'b',False,'A'),
 (0,'b',False,'B'),
 (0,'c',False,'A'),
 (0,'c',False,'B'),
 (50,'a',True,'A'),
 (50,'a',True,'B'),
 (50,'b',True,'A'),
 (50,'b',True,'B'),
 (50,'c',True,'A'),
 (50,'c',True,'B'),
 (50,'a',False,'A'),
 (50,'a',False,'B'),
 (50,'b',False,'A'),
 (50,'b',False,'B'),
 (50,'c',False,'A'),
 (50,'c',False,'B'),
 (100,'a',True,'A'),
 (100,'a',True,'B'),
 (100,'b',True,'A'),
 (100,'b',True,'B'),
 (100,'c',True,'A'),
 (100,'c',True,'B'),
 (100,'a',False,'A'),
 (100,'a',False,'B'),
 (100,'b',False,'A'),
 (100,'b',False,'B'),
 (100,'c',False,'A'),
 (100,'c',False,'B'),
 (150,'a',True,'A'),
 (150,'a',True,'B'),
 (150,'b',True,'A'),
 (150,'b',True,'B'),
 (150,'c',True,'A'),
 (150,'c',True,'B'),
 (150,'a',False,'A'),
 (150,'a',False,'B'),
 (150,'b',False,'A'),
 (150,'b',False,'B'),
 (150,'c',False,'A'),
 (150,'c',False,'B'),
 (200,'a',True,'A'),
 (200,'a',True,'B'),
 (200,'b',True,'A'),
 (200,'b',True,'B'),
 (200,'c',True,'A'),
 (200,'c',True,'B'),
 (200,'a',False,'A'),
 (200,'a',False,'B'),
 (200,'b',False,'A'),
 (200,'b',False,'B'),
 (200,'c',False,'A'),
 (200,'c',False,'B')]

(new lines added to make it easier to verify)

Related