I\'ve always found it awkward to have a function or expression that requires use of the values, as well as indices, of a list (or array, applies just the same) in Haskell.>
Borrowing enumerate is fine and encouraged. However, it can be made a bit lazier by refusing to calculate the length of its argument:
enumerate = zip [0..]
(In fact, it's common to just use zip [0..] without naming it enumerate.) It's not clear to me why you think your second example should be costlier in either time or space. Remember: indexing is O(n), where n is the index. Your complaint about the unwieldiness of fst and snd is justified, and can be remedied with pattern-matching:
validQueens' xs = and [abs (y - x) /= j - i | (i, x) <- l, (j, y) <- l, i < j]
where l = zip [0..] xs
Now, you might be a bit concerned about the efficiency of this double loop, since the clause (j, y) <- l is going to be running down the entire spine of l, when really we just want it to start where we left off with (i, x) <- l. So, let's write a function that implements that idea:
pairs :: [a] -> [(a, a)]
pairs xs = [(x, y) | x:ys <- tails xs, y <- ys]
Having made this function, your function is not too hard to adapt. Pulling out the predicate into its own function, we can use all instead of and:
validSingleQueen ((i, x), (j, y)) = abs (y - x) /= j - i
validQueens' xs = all validSingleQueen (pairs (zip [0..] xs))
Or, if you prefer point-free notation:
validQueens' = all validSingleQueen . pairs . zip [0..]