[Haskell-cafe] Computing lazy and strict list operations at the same time

Brandon Moore brandonm at yahoo-inc.com
Wed Sep 27 11:59:42 EDT 2006


Andrew Pimlott wrote:
> This is a follow-up to a thread from June-July[1].  The question was how to
> write the function
>
>     initlast :: [a] -> ([a], a)
>     initlast xs = (init xs, last xs)
>
> so that it can be consumed in fixed space:
>
>     main = print $ case initlast [0..1000000000] of
>                      (init, last) -> (length init, last)
>
> Attempts were along the lines of
>
>     initlast :: [a] -> ([a], a)
>     initlast [x]    = ([], x)
>     initlast (x:xs) = let (init, last) = initlast xs
>                       in  (x:init, last)
>
> I seemed obvious to me at first (and for a long while) that ghc should
> force both computations in parallel; but finally at the hackathon
> (thanks to Simon Marlow) I realized I was expecting magic:  The elements
> of the pair are simply independent thunks, and there's no way to "partly
> force" the second (ie, last) without forcing it all the way.
According to the stuff about "selector thunks", it seems this should work

initlast [x] = ([],[x])
initlast (x:xs) =
let ~(init,last) = initlast xs
in (x:init, last)

Sometimes it does compile to a program that runs in constant space, 
sometimes it doesn't!

I've sent a message to the list with a heap profile of a run on 10M 
numbers, but it's being held for moderation because it's too big.

Brandon



More information about the Haskell-Cafe mailing list