Look at the inferred type of your code:
> combine2 xs ys = [x : ys | x <- xs]
> :type combine2
combine2 :: [a] -> [a] -> [[a]]
So you’re returning “list of list of a” when you meant to return “list of a”. The compiler sees that these are both lists, and tries to match the element types, but finds that one contains “list of a” while the other is just “a”. Since the type variable a occurs in the type “list of a”, if they were equal, this would be a sort of infinite loop: a = [a] = [[a]] = [[[a]]] = …, which is almost never what you meant to do, so the typechecker disallows it.
Your code does this:
combine2 [1, 2, 3] [4, 5, 6]
=
[ 1 : [4, 5, 6]
, 2 : [4, 5, 6]
, 3 : [4, 5, 6]
]
=
[ [1, 4, 5, 6]
, [2, 4, 5, 6]
, [3, 4, 5, 6]
]
When you want it to do this:
combine2 [1, 2, 3] [4, 5, 6]
=
[1, 2, 3, 4, 5, 6]
A solution with list comprehensions is to iterate over each list, and then each item within those lists:
combine2' xs ys = [z | zs <- [xs, ys], z <- zs]
In combine2' [1, 2, 3] [4, 5, 6], first zs is set to [1, 2, 3], so z is set to 1, then 2, then 3; then zs is set to [4, 5, 6], so z is set to 4, then 5, then 6.
You can also think of this equationally, in terms of the desugaring of list comprehensions using concatMap:
[z | zs <- [xs, ys], z <- zs]
=
concatMap (\ zs -> concatMap (\ z -> [z]) zs) [xs, ys]
=
concatMap (\ zs -> concatMap pure zs) [xs, ys]
=
concatMap (\ zs -> concat (map pure zs)) [xs, ys]
=
concatMap (\ zs -> zs) [xs, ys]
=
concatMap id [xs, ys]
=
concat (map id [xs, ys])
=
concat [xs, ys]
=
foldr (++) [] [xs, ys]
=
xs ++ ys ++ []
=
xs ++ ys
Essentially, you are concatenating all of the input lists, where “all” happens to be only 2 in this case.