That'll cost you one goldbach (*groan*)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import Control.Arrow
import Control.Monad
import Control.Monad.State

import Data.Maybe
import Data.Traversable

import Analytics.Theory.Number   -- http://lpaste.net/107480 for the Prime type

import Data.Stream               -- http://lpaste.net/107665 

-- P40 Goldbach's conjecture.

-- Solution to problem posted at http://lpaste.net/108019

goldbach :: Integer -> Maybe (Prime, Prime)
goldbach n = -- no: (evalState (pickPrimes n) primes)
   {-- Ick: listToMaybe [(x, y) | (x, rest) <- choose primes, x < n - 2,
                         let y = n - x, isPrime y]
 --}
   listToMaybe (choose primes >>= \(x, rest) -> 
                guard (x < pred n && isPrime (n - x)) >>
                return (x, n - x))

{-- nah:
pickPrimes :: Integer -> State (Stream Prime) (Prime, Prime)
pickPrimes n = get >>= return . choose >>= \(x, rest) -> 
   guard (x < n - 2) >> put rest >>
   let y = n - x in guard (isPrime y) >> return (x, y)
 --}

-- Nope:
 -- listToMaybe [(x, y) | x <- choose primes, x < n - 2, 
                                   -- let y = n - x, isPrime y]

goldbachs :: Integer -> Integer -> [(Prime, Prime)]
goldbachs sm lrg = fromJust (for [half sm .. half lrg] (goldbach . (* 2)))

half :: Integer -> Integer
half = flip div 2 . succ

-- ... and there's your one-liner. I love for-loops!

goldbachsGT :: Integer -> Integer -> Integer -> [(Integer, (Prime, Prime))]
goldbachsGT a b min = goldbachs (max a $ 2 * min + 1) b >>= \(x, y) ->
   guard (x > min && y > min) >> return (x + y, (x, y))

{--

*Main> goldbachsGT 2 3000 50 ~>
[(992,(73,919)),(1382,(61,1321)),(1856,(67,1789)),(1928,(61,1867)),
 (2078,(61,2017)),(2438,(61,2377)),(2512,(53,2459)),(2530,(53,2477)),
 (2618,(61,2557)),(2642,(103,2539))]
*Main> length it ~> 10

 --}