[Haskell-cafe] Computing lazy and strict list operations at the
same time
Robert Dockins
robdockins at fastmail.fm
Mon Jun 19 13:28:08 EDT 2006
On Jun 19, 2006, at 12:50 PM, Duncan Coutts wrote:
> On Mon, 2006-06-19 at 17:03 +0100, Jon Fairbairn wrote:
>> On 2006-06-19 at 15:24-0000 "C Rodrigues" wrote:
>>> Here's a puzzle I haven't been able to solve. Is it possible to
>>> write the
>>> initlast function?
>>>
>>> There are functions "init" and "last" that take constant stack
>>> space and
>>> traverse the list at most once. You can think of traversing the
>>> list as
>>> deconstructing all the (:) [] constructors in list.
>>>
>>> init (x:xs) = init' x xs
>>> where init' x (y:ys) = x:init' y ys
>>> init' _ [] = []
>>>
>>> last (x:xs) = last' x xs
>>> where last' _ (y:ys) = last' y ys
>>> last' x [] = x
>>>
>>> Now, is there a way to write initlast :: [a] -> ([a], a) that
>>> returns the
>>> result of init and the result of last, takes constant stack
>>> space, and
>>> traverses the list only once? Calling reverse traverses the list
>>> again. I
>>> couldn't think of a way to do it, but I couldn't figure out why
>>> it would be
>>> impossible.
>>
>>
>> il [] = error "foo"
>> il [x] = ([], x)
>> il (x:xs) = cof x (il xs)
>> where cof x ~(a,b) = (x:a, b)
>> -- !
>
>> From a quick test, it looks like none of our suggested solutions
> actually work in constant space.
> main = interact $ \s ->
> case il s of
> (xs, x) -> let l = length xs
> in l `seq` show (l,x)
>
> using ghc:
> ghc -O foo.hs -o foo
> ./foo +RTS -M10m -RTS < 50mb.data
>
> using runhugs:
> runhugs foo.hs < 50mb.data
>
> in both cases and for each of the three solutions we've suggested the
> prog runs out of heap space where the spec asked for constant heap
> use.
Actually, the OP asked for constant stack space, which is quite
different and much easier to achieve.
> So what's wrong? In my test I was trying to follow my advice that we
> should consume the init before consuming the last element. Was that
> wrong? Is there another way of consuming the result of initlast that
> will work in constant space?
That is, nonetheless, an interesting question.
> Note that by changing discarding the x we do get constant space use:
> main = interact $ \s ->
> case il s of
> (xs, x) -> let l = length xs
> in l `seq` show l -- rather than 'show (l,x)'
>
> Why does holding onto 'x' retain 'xs' (or the initial input or some
> other structure with linear space use)?
>
> Duncan
Rob Dockins
Speak softly and drive a Sherman tank.
Laugh hard; it's a long way to the bank.
-- TMBG
More information about the Haskell-Cafe
mailing list