[GHC] #876: stack overflow on 'length . filter odd $ [0
.. 999999999]'
Jan-Willem Maessen
jmaessen at alum.mit.edu
Thu Aug 31 09:42:24 EDT 2006
On Aug 31, 2006, at 6:29 AM, Malcolm Wallace wrote:
> Bulat Ziganshin <bulat.ziganshin at gmail.com> wrote:
>
>>> It makes sense to me that the above behaviour is seen: length is
>>> now a good
>>> consumer, but it generates 1+(1+(1+(1+... as it is consuming, and
>>> this causes a stack overflow. I don't think we can fix this while
>>> staying with fold/build fusion, so it looks to me like the patch
>>> should be reverted and the whole problem looked at post-6.6.
>>
>> in general, for any function we can either implement
>> 1) good consumer based on using foldr
>> 2) tail-recursion
>>
>> are you agree?
>
> I'd like to point out that, if you are prepared to abandon foldr/build
> fusion in favour of hylo fusion, you can code good consumers using
> either foldr or foldl. (Length is a foldl, because it uses an
> accumulator.) Foldl is tail-recursive, but this does not prevent it
> being a good consumer, provided your framework of fusion laws is
> sufficiently flexible.
Actually, it's sufficient to do good arity-raising transformations,
and use the definition:
foldl f z xs = foldr (\x k a -> k (f a x)) id xs z
This yields code which looks a bit like this:
let loop [] = id
loop (x:xs) = let k = loop xs in (\a -> k (f a x))
in loop xs z
In the pH compiler we recognized this idiom (and its generalizations
to multiple accumulating parameters) and arity-raised loop as follows:
let loop [] a = a
loop (x:xs) a = loop xs (f a x)
in loop xs z
So we *can* make foldl into a good consumer---it's not even
particularly difficult---but it relies rather heavily on getting some
of the knock-on program transformations to be reliable. That means
making sure we recognize the above pattern before it gets mangled by
other optimizations. A possibility to avoid this problem is just to
look for over-saturated applications of "loop" and then attempt arity
expansion and see if any under-saturated recursive calls remain.
There are alternatives that involve real interprocedural arity
analysis, but that's hard enough that I've never tried to do it
except on paper.
We can actually play some similar games with functions which use an
accumulating parameter but exit early, or which can be modeled by
little state machines, but the transformations required to get "the
code you want" in these cases involve actual arity and closure
analysis rather than simple pattern-matching (which suffices for the
foldl-using-foldr trick). A look at recent papers by Olin Shivers
should give an idea of the kind of tricks required.
Hylo fusion is great if you want to deforest non-cleverly written
library code or non-lists. Jacob Schwartz (now at Bluespec) did a
hylo fusion pass for pH---but the knock-on transformations proved a
bit problematic. I speculate that if you do a full-on analysis a la
jhc you'd get really great code---but the GRIN argument was that you
could just skip all this deforestation nonsense at that point as it
happened implicitly during the analysis.
-Jan-Willem Maessen
>
> Regards,
> Malcolm
> _______________________________________________
> Glasgow-haskell-users mailing list
> Glasgow-haskell-users at haskell.org
> http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 2425 bytes
Desc: not available
Url : http://www.haskell.org//pipermail/glasgow-haskell-users/attachments/20060831/46106eb3/smime.bin
More information about the Glasgow-haskell-users
mailing list