Running the following program will print "space overflow: current size 8388608 bytes." I have read this and this, but still don't know how to resolve my problem. I am using foldr, shouldn't it be guaranteed to be "tail recursive"?
I feel great about Haskell so far until I know I should prevent "space overflow" when using the powerful recursion. :)
module Main where
import Data.List
value a b =
let l = length $ takeWhile (isPrime) $ map (\n->n^2 + a * n + b) [0..]
in (l, a ,b)
euler27 = let tuple_list = [value a b | a <-[-999..999] , b <- [-999..999]]
in foldr (\(n,a,b) (max,v) -> if n > max then (n , a * b) else (max ,v) ) (0,0) tuple_list
main = print euler27
EDIT: remove the definiton of isPrime
for simplicity
As pierr answered, you should use foldl'
. For more details:
foldl'
calculates its "left-side" before giving it to your fold step.foldr
gives your fold step a "thunk" for the right-side value. This "thunk" will be calculated when needed.Let's make a sum with foldr
and see how it evaluates:
foldr (+) 0 [1..3]
1 + foldr (+) 0 [2..3]
1 + 2 + foldr (+) 0 [3]
1 + 2 + 3 + foldl (+) 0 [] -- this is a big thunk..
1 + 2 + 3 + 0
1 + 2 + 3
1 + 5
6
And with foldl'
: (tag omitted in code because SO doesn't display it nicely)
foldl (+) 0 [1..3]
-- seq is a "strictness hint".
-- here it means that x is calculated before the foldl
x `seq` foldl (+) x [2..3] where x = 0+1
foldl (+) 1 [2..3]
x `seq` foldl (+) x [3] where x = 1+2
foldl (+) 3 [3]
x `seq` foldl (+) x [] where x = 3+3
foldl (+) 6 []
6
In good uses for foldr
, which don't leak. the "step" must either:
Examples of good foldr
usage:
-- in map, the step returns the structure head
-- without evaluating the "right-side"
map f = foldr ((:) . f) []
filter f =
foldr step []
where
step x rest
| f x = x : rest -- returns structure head
| otherwise = rest -- returns right-side as is
any f =
foldr step False
where
-- can use "step x rest = f x || rest". it is the same.
-- version below used for verbosity
step x rest
| f x = True -- ignore right-side
| otherwise = rest -- returns right-side as is
replace
foldr (\(n,a,b) (max,v) -> if n > max then (n , a * b) else (max ,v) ) (0,0) tuple_list
with
foldl' (\(max ,v) (n,a,b) -> if n > max then (n , a * b) else (max ,v) ) (0,0) tuple_list
solved this problem, should that suggest we should always prefer to use foldl' instead of other variants(foldl,foldr)?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With