[Haskell-cafe] Strange memory consumption problems in something
that should be tail-recursive
Bernie Pope
bjpop at csse.unimelb.edu.au
Tue Feb 13 16:32:38 EST 2007
Creighton Hogg wrote:
>
>
> On 2/13/07, *Duncan Coutts* <duncan.coutts at worc.ox.ac.uk
> <mailto:duncan.coutts at worc.ox.ac.uk>> wrote:
>
> On Tue, 2007-02-13 at 15:27 -0500, Jefferson Heard wrote:
> > Hi, I am running the following code against a 210 MB file in an
> attempt to
> > determine whether I should use alex or whether, since my needs
> are very
> > performance oriented, I should write a lexer of my own. I
> thought that
> > everything I'd written here was tail-recursive
>
> Isn't that exactly the problem - that it's tail recursive? You do not
> want it to be tail recursive since then it must consume the whole
> input
> before producing any output. You want it to be as lazy as possible so
> that it can start producing tokens as soon as possible without
> having to
> consume everything.
>
>
> This may be silly of me, but I feel like this is an important point:
> so you're saying that tail recursion, without strictness, doesn't run
> in constant space?
It is an important point, and a classic space bug (see foldl in the
Prelude).
It it not the fault of tail recursion per se, in fact tail recursion is
often important in Haskell too.
> So for example in the case of,
> facTail 1 n' = n'
> facTail n n' = facTail (n-1) (n*n')
The problem with this example is that it will build up an expression of
the form:
(n1 * n2 * n3 .....)
in the second argument. It's size will be proportional to the number of
recursive calls made (n).
> You'll just be building a bunch of unevaluated thunks until you hit
> the termination condition?
>
To fix it you will want the function to evaluate its second argument
eagerly:
facTail n n' = facTail (n-1) $! (n*n')
Cheers,
Bernie.
More information about the Haskell-Cafe
mailing list