Below we have two seemingly functionally equivalent programs. For the first the memory remains constant, whereas for the second the memory explodes (using ghc 7.8.2 & bytestring-0.10.4.0 in Ubuntu 14.04 64-bit):
Non-exploding :
--NoExplode.hs
--ghc -O3 NoExplode.hs
module Main where
import Data.ByteString.Lazy as BL
import Data.ByteString.Lazy.Char8 as BLC
num = 1000000000
bytenull = BLC.pack ""
countDataPoint arg sum
| arg == bytenull = sum
| otherwise = countDataPoint (BL.tail arg) (sum+1)
test1 = BL.last $ BL.take num $ BLC.cycle $ BLC.pack "abc"
test2 = countDataPoint (BL.take num $ BLC.cycle $ BLC.pack "abc") 0
main = do
print test1
print test2
Exploding :
--Explode.hs
--ghc -O3 Explode.hs
module Main where
import Data.ByteString.Lazy as BL
import Data.ByteString.Lazy.Char8 as BLC
num = 1000000000
bytenull = BLC.pack ""
countDataPoint arg sum
| arg == bytenull = sum
| otherwise = countDataPoint (BL.tail arg) (sum+1)
longByteStr = BL.take num $ BLC.cycle $ BLC.pack "abc"
test1 = BL.last $ longByteStr
test2 = countDataPoint (BL.take num $ BLC.cycle $ BLC.pack "abc") 0
main = do
print test1
print test2
Additional details :
The difference is that inExplode.hs I have taken BL.take num $ BLC.cycle $ BLC.pack "abc" out of the definition of test1, and assigned it to its own value longByteStr.
Strangely if we comment out either print test1 or print test2 in Explode.hs (but obviously not both), then the program does not explode.
Is there a reason memory is exploding in Explode.hs and not in NoExplode.hs, and also why the exploding program (Explode.hs) requires both print test1 and print test2 in order to exlode?