Non tail-recursive function not blowing up in GHCi

2019-06-20 04:26发布

问题:

I was expecting to see my stack blow with the following code.. yet it didn't:

*Main> let blowwss x = if x == 0 then 0 else (1 + blowwss (x-1))
*Main> blowwss 1000000
1000000

The function doesn't seem to be tail-recursive, so I'm wondering what may I be missing. Is GHCi's stack bigger than I thought (how can I see it's stack size, btw?). Is it using some kind of trampoline to get over this? Is it smart enough to convert the function to its iterative counterpart?

Thanks

回答1:

GHCi's stack is bigger than you think. IIRC, the default stack size is 500M for GHCi, whereas the default stack size for a compiled program is currently 8M. You can set a smaller limit yourself to see that you get a stack overflow (or you can increase your argument significantly).

$ ghci +RTS -K1M
GHCi, version 7.6.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> let blowwss x = if x == 0 then 0 else (1 + blowwss (x-1))
Prelude> blowwss 1000000
*** Exception: stack overflow

Note that GHC has a stack size limit purely to prevent infinite / unexpectedly deep loops in situations that are most likely programming errors. In principle, the stack can grow indefinitely (constrained by the system memory, of course). Even if you specify a large stack size, the stack actually starts much smaller, but can grow up to the limit. There's currently discussion about possibly removing the limit completely in future versions of GHC.



回答2:

You have used a too small value for that. I've moved your function on a separate file

blowwss x = if x == 0 then 0 else (1 + blowwss (x-1))

main = do
  print $ blowwss 10000000000
  print $ blowwss 10000000000000

and then compiled and run

[mihai@esgaroth tmp]$ ghc --make 1.hs
[1 of 1] Compiling Main             ( 1.hs, 1.o )
Linking 1 ...
[mihai@esgaroth tmp]$ ./1
Stack space overflow: current size 8388608 bytes.
Use `+RTS -Ksize -RTS' to increase it.

Running this in GHCI I get a high load and then a stack overflow. That is because GHCi's stack is higher, I guess somewhere around 512M.