
Claus Reinke wrote:
i'm just guessing here, but if that is indeed the problem, you would need to exert more control over what is evaluated when and shared where:
- evaluate rResult synchronously with rTokens, instead of rResult long after rTokens has unfolded the reply - evaluate rResult independent of rTokens, on a separate copy of reply
Brandon Michael Moore wrote:
It's the same problem you see in
--argument to break sharing input () = 'a' : input ()
main = let text = input() in putStr (text ++ [last text])
Ah, of course. That's what's going on:
result = rResult reply -- Lazy; has value when parsing is done extra = case result ... -- Lazy; has value when parsing is done parsed = rTokens reply -- Has some values "immediately"
On evaluating 'parsed', the DList of tokens gets expanded. But by keeping a reference to 'reply' via 'result', this expanded list has to be kept in memory! I mean, the definition of 'result' formally specifies that it depends on the hole 'reply' and the GC may not throw away parts of it. This is similar to the described space leaks in http://citeseer.ist.psu.edu/sparud93fixing.html I believe that a single deconstruction of the reply as in let tokens = case args of ["free"] -> rTokens reply ["leak"] -> case reply of Reply { rResult = result, rTokens = parsed } -> let extra = maybe (D.singleton $ Token {tText='!'}) (const D.empty) result in D.append parsed extra is a cure for your space leak. Regards, apfelmus