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

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

&gt; 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] -&gt; [(a, a)]
createGroups [] = []
createGroups (x:xs) = map ((,) x) xs ++ createGroups xs

&gt; 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] -&gt; [(a, a)]
createGroups ls @ (_ : xs) = [(x, pair) | x &lt;- ls, pair &lt;- xs]

&gt; 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] -&gt; [[(a, a)]]
createGroups li@(x : xs) = do
  first &lt;- li
  return (getPairs first xs)
  where
    getPairs item pairings = do
      pair &lt;- pairings
      return (item, pair)

&gt; 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.