IMPORTANT: See Will Ness' comment below.
Your question implies that the order doesn't matter. (But since the lists may be infinite, the order may be more important than you think!) Anyway, if the order doesn't matter, and you have encountered list comprehensions, that's one approach you could use. Here's an example.
λ> let xs = "abcdef"
λ> let ys = "ABCDEFGHI"
λ> [(x,y) | x <- xs, y <- ys]
[('a','A'),('a','B'),('a','C'),('a','D'),('a','E'),('a','F'),('a','G'),('a','H'),('a','I'),('b','A'),('b','B'),('b','C'),('b','D'),('b','E'),('b','F'),('b','G'),('b','H'),('b','I'),('c','A'),('c','B'),('c','C'),('c','D'),('c','E'),('c','F'),('c','G'),('c','H'),('c','I'),('d','A'),('d','B'),('d','C'),('d','D'),('d','E'),('d','F'),('d','G'),('d','H'),('d','I'),('e','A'),('e','B'),('e','C'),('e','D'),('e','E'),('e','F'),('e','G'),('e','H'),('e','I'),('f','A'),('f','B'),('f','C'),('f','D'),('f','E'),('f','F'),('f','G'),('f','H'),('f','I')]
Note that all of the tuples involving 'a'
are printed first, then those involving 'b'
, and so on. Why does that matter? Well suppose the list is infinite. A query like this will return instantly:
(1,'a') `elem` [(x,y) | x <- [1..], y <- ['a'..]]
But one like this will take a LOOOOONG time:
(200000,'a') `elem` [(x,y) | x <- [1..], y <- ['a'..]]
If order matters, or you haven't encountered list comprehensions, or don't want to use them, luqui's approach is probably what you're looking for.