It's a pity you unaccepted @leftaroundabout's solution. It has a lot more to it. For example, the other solution has a heuristic "all numbers must be less than n" (what do you do for problems where you don't have this heuristic?), and a few other steps that make it harder to prove that it actually is a solution to goldbach's problem - e.g. can you demonstrate that way ot enumerating primes is going to put together all useful pairs of primes? (It does, but can you demonstrate it? This is the weakness of that solution)
So here I will show how you can build the solution @leftaroundabout presented, without saying the word "monad".
The problem with the list comprehension you built at first is that it searches the solution "depth-first" - take one element from the first list, then try all combinations with this element. However, if there is a infinite number of combinations, you will never get to enumerate any pairs with the second element from the first list. This is where we need to talk about "breadth-first" search for solutions.
Let's say gen
is a generator of solutions:
gen x = map (\y -> (x,y)) -- construct pairs for a given element x
Let's say gens
is a generator of generators of solutions:
gens xs ys = map (\x -> gen x ys) xs
All we need to do now, is enumerate solutions by taking one solution from each generator at a time. Mind you, if the number of generators is infinite, we can't just take them one by one - that way we will never get to take the second solution from the first generator, so we need to "step" them somehow:
om xs = f [] [] xs where -- this is your omega enumerating solutions
-- from generator of generators
f [] [] [] = [] -- this is where the pot stops cooking
f [] gs [] = f gs [] []
f [] gs (g:gens) = f (g:gs) [] gens -- ok, took one solution from all generators -
-- add one generator to the list of generators we enumerate
-- next time - this is how we "step" the generators
f ([]:gs) gs' gens = f gs gs' gens -- generator eliminator: last solution was taken
-- from one generator
f ((x:xs):gs) gs' gens = x : f gs (xs:gs') gens -- take one solution from the first
-- generator, and move the rest of the generator to the list
-- for the next iteration
That's it.
> find (\(x,y) -> x+y==190) $ om $ gens primes primes
Just (179,11)
Now, to efficiency. It is all in gens
and gen
. Add a condition to gens
to takeWhile ((<=n) . (x+))
, and it will work even if Goldbach's conjecture is wrong (but you don't have to add it at all). Add a condition to gen
to takeWhile (<=x)
, and you will enumerate only the pairs where the first prime is greater than the other.