In ghci, I observe no spectacular speedup over your list version. No luck !

Edit :
Indeed, with -O2 as suggested by Chris Kuklewicz, this solution is eight times faster than your for n=5000. Combined with Hammar insight of doing sums modulo 10^6, I get a solution that is fast enough (find the hopefully correct answer in about 10 seconds on my machine):

(I broke the psCache abstraction, so you should use psArr instead of psOpt; this ensures that different call to psArr will reuse the same memoized array. This is useful when you write find ((== 0) . ...)... well, I thought it was better not to publish the complete solution.)

That is a good trick, but it turns out that this peculiar challenge can be solved without this optimization.
–
Chris KuklewiczApr 26 '11 at 8:56

2

True, but it applies to a lot of PE problems. One favorite trick of mine is to define a newtype with a Num instance that does modular arithmetic. That way I can reuse a lot of existing code.
–
hammarApr 26 '11 at 9:36

1

@Chris Kuklewicz I tested with my Array implementation, the modular trick speeds up the computation of p(n) for "the right n" from 40s to 15s on my machine. Not fundamental, but still pretty nice.
–
gascheApr 26 '11 at 9:56

How can you perform the sum first and then multiply? It's not the same. ax+by ≠ (a+b)(x+y)… unless you're thinking of something else that I didn't understand?
–
ShreevatsaRApr 25 '11 at 22:08

Oh you're right; for some reason I was thinking that sign was the same for all of them, so that cx+cy = c(x+y), but it's not the same. My mistake. It might be faster to use id and negate instead of *1 and *-1 respectively, though that would be a minor speedup at best.
–
Dan BurtonApr 26 '11 at 0:33

Inspired by your question, I have used your approach to solve Euler 78 with Haskell. So I can give you some performance hints.

Your cached list of pents should be good as it is.

Pick some large number maxN to bound your search for (p n).

The plan is to use an (Array Int64 Integer) to memorize the result of (p n), with lower bound 0 and upper bound maxN. This requires defining the array in terms of 'p' and 'p' in terms of the array, they are mutually recursively defined:

Redefine (p n) to (pArray n) to look up recursive calls to 'p' in the array A.

Use your new pArray with Data.Array.IArray.listArray to create the array A.