Search code examples
haskellrecursionstack-overflow

Haskell - Recursion Stack Overflow


I am trying to sum all n from 1 to a very large number (10**9 for now) but it gives stack overflow. Also I don't think putting a stop at 1 and doing the sum n in different rows is the most efficient way but the code below is all my knowledge for Haskell. I really don't know much about functional programming and I would like as much explanation as possible. (Also I have tried putting $! strict in the last line which was told in other places but it changed nothing. I would be glad if you explained the most efficient way I could do this recursive function.)

main :: IO()

summ 1 = 1
summ n = 1/(n**2) + summ (n-1)

expected_value = pi*pi/6
errorPercent n = n / expected_value * 100

main = do
    putStr "%"
    print (errorPercent (summ $! (10**9)))

Solution

  • The problem here is that sums can not start being computed until the whole 10^9 recursion calls are over. Essentially, you are computing

    1/(n**2) + ( 1/((n-1)**2) + ( 1/((n-2)**2) + ....
    

    and the parentheses prevent to start summing. Instead, we would like to have

    (( 1/(n**2) + 1/((n-1)**2) ) + 1/((n-2)**2) ) + ....
    

    The easiest way is to use an "accumulator" additional argument:

    summ 1 acc = 1 + acc
    summ n acc = summ (n-1) $! acc + 1/(n**2)
    
    main = do
        putStr "%"
        print (errorPercent (summ (10^9) 0))  -- set acc to 0 at the beginning
    

    For improving the performance, I'd recommend to add a type signature to summ e.g. summ :: Int -> Double -> Double.


    Full program below. This runs in 12s here (ghc -O2).

    summ :: Int -> Double -> Double
    summ 1 acc = 1 + acc
    summ n acc = summ (n-1) $! acc + 1 / (fromIntegral n**2)
    
    main :: IO ()
    main = do
        putStr "%"
        print (summ (10^9) 0)  -- set acc to 0 at the beginning