# Producing all possible combinations of a list

I've written a function that produces all combinations of elements in a given list:

createGroups :: [a] -> [[(a, a)]]
createGroups li@(x : xs) = map (\el -> map (\el2 -> (el, el2)) xs) li


These nested maps seem quite messy -- is there a better way to do this?

It is possible that I'm misunderstanding the problem, but based on your description, I would expect the type of createGroups to be [a] -> [(a, a)] (A flat list, not a list of lists.)

I believe there is bug in your code. Take a look:

> createGroups [1..3]
[[(1,2),(1,3)],[(2,2),(2,3)],[(3,2),(3,3)]]


This result is not what I would expect based on your problem description. Given a list of [1, 2, 3], I would expect the output to be [(1,2),(1,3),(2,3)].

One way to achieve this output is the following:

createGroups :: [a] -> [(a, a)]
createGroups [] = []
createGroups (x:xs) = map ((,) x) xs ++ createGroups xs

> createGroups [1..3]
[(1,2),(1,3),(2,3)


Here is another function that outputs a "flat list" containing the same pairs as your original function, however it's been rewritten to use list comprehension:

createGroups :: [a] -> [(a, a)]
createGroups ls @ (_ : xs) = [(x, pair) | x <- ls, pair <- xs]

> createGroups [1..3]
[(1,2),(1,3),(2,2),(2,3),(3,2),(3,3)]


Lastly, here is a function that produces output identical to yours, rewritten using the monad instance of list:

createGroups :: [a] -> [[(a, a)]]
createGroups li@(x : xs) = do
first <- li
return (getPairs first xs)
where
getPairs item pairings = do
pair <- pairings
return (item, pair)

> createGroups [1..3]
[[(1,2),(1,3)],[(2,2),(2,3)],[(3,2),(3,3)]]


Hopefully this gives you some ideas of different ways to write your function.