很遗憾您没有接受@leftaroundabout 的解决方案。它还有很多。例如,另一个解决方案有一个启发式“所有数字必须小于 n”(如果你没有这个启发式的问题,你会怎么做?),以及一些其他的步骤,这使得它更难证明它实际上是是解决哥德巴赫问题的方法 - 例如你能证明枚举素数的方式将把所有有用的素数对放在一起吗? (确实如此,但你能证明一下吗?这是该解决方案的弱点)
所以在这里我将展示如何构建@leftaroundabout 提出的解决方案,而不用说“monad”这个词。
您最初构建的列表理解的问题在于它搜索“深度优先”的解决方案 - 从第一个列表中获取一个元素,然后尝试使用该元素的所有组合。但是,如果有无限数量的组合,您将永远无法使用第一个列表中的第二个元素枚举任何对。这就是我们需要讨论“广度优先”搜索解决方案的地方。
假设gen 是解决方案的生成器:
gen x = map (\y -> (x,y)) -- construct pairs for a given element x
假设gens 是解决方案生成器的生成器:
gens xs ys = map (\x -> gen x ys) xs
我们现在需要做的就是通过一次从每个生成器中获取一个解决方案来枚举解决方案。请注意,如果生成器的数量是无限的,我们不能一个接一个地获取它们——那样我们将永远无法从第一个生成器中获取第二个解决方案,因此我们需要以某种方式“步进”它们:
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
就是这样。
> find (\(x,y) -> x+y==190) $ om $ gens primes primes
Just (179,11)
现在,为了效率。全部在gens 和gen 中。给gens加一个条件到takeWhile ((<=n) . (x+)),即使哥德巴赫猜想错了也能行(但你根本不用加)。将条件添加到gen 到takeWhile (<=x),您将只枚举第一个质数大于另一个质数的对。