reversing big list with constant heap space used

How to solve task of reversing big list with constant heap space used? Amount of heap space used grows exponentially in following examples: 1: main = putStrLn.show.head $reverse [1..10000000] 2 (GHC): import Data.List main = putStrLn.show.head $foldl' (flip (:)) [] [1..10000000] 3 (GHC): import Control.Monad main = foldM (\x y -> return $ y:x) [] [1..10000000] >>= putStrLn.show.head -- Best regards, Sergey Perminov

On Wed, 16 May 2007, Sergey Perminov wrote:
How to solve task of reversing big list with constant heap space used?
By avoiding 'reverse'?
Amount of heap space used grows exponentially in following examples:
1: main = putStrLn.show.head $reverse [1..10000000]
Data.List.last I think that in every particular case you have to find out how to avoid 'reverse'. Especially if you have two 'reverse's like in reverse . dropWhile p . reverse there are more efficient solutions.

I think that in every particular case you have to find out how to avoid 'reverse'. Especially if you have two 'reverse's like in reverse . dropWhile p . reverse there are more efficient solutions.
Just from curiosity, what *is* an efficient way to do rDropWhile? Here's something which at least avoids 2 reverses: rDropWhile = doRDropWhile [] doRDropWhile accum f [] = [] doRDropWhile accum f (x:xs) | f x = doRDropWhile (x:accum) f xs | otherwise = reverse (x:accum) ++ doRDropWhile [] f xs I assume this is not in Data.List to discourage people from doing things to the right side of lists... it's still useful for string stuff where ByteString would be overkill though.

Evan Laforge wrote:
I think that in every particular case you have to find out how to avoid 'reverse'. Especially if you have two 'reverse's like in reverse . dropWhile p . reverse there are more efficient solutions.
Just from curiosity, what *is* an efficient way to do rDropWhile? Here's something which at least avoids 2 reverses:
rDropWhile = doRDropWhile []
doRDropWhile accum f [] = [] doRDropWhile accum f (x:xs) | f x = doRDropWhile (x:accum) f xs | otherwise = reverse (x:accum) ++ doRDropWhile [] f xs
How about a fold? rDropWhile f = either (const []) id . foldr g (Left ()) where g x (Left _ ) = if f x then Left () else Right [x] g x (Right xs) = Right (x:xs)
I assume this is not in Data.List to discourage people from doing things to the right side of lists... it's still useful for string stuff where ByteString would be overkill though.
Indeed, the list data structure is intended to be used from the left only. For double-end access, there are queues and Data.Sequence. Regards, apfelmus

On Wed, 16 May 2007, Evan Laforge wrote:
I think that in every particular case you have to find out how to avoid 'reverse'. Especially if you have two 'reverse's like in reverse . dropWhile p . reverse there are more efficient solutions.
Just from curiosity, what *is* an efficient way to do rDropWhile? Here's something which at least avoids 2 reverses:
rDropWhile = doRDropWhile []
doRDropWhile accum f [] = [] doRDropWhile accum f (x:xs) | f x = doRDropWhile (x:accum) f xs | otherwise = reverse (x:accum) ++ doRDropWhile [] f xs
http://www.haskell.org/pipermail/libraries/2005-August/004217.html dropWhileRev :: (a -> Bool) -> [a] -> [a] dropWhileRev p = foldr (\x xs -> if p x && null xs then [] else x:xs) []

David House wrote:
On 16/05/07, Sergey Perminov
wrote: How to solve task of reversing big list with constant heap space used?
I think that as lists are singly-linked in Haskell, reversing a list will always be O(n) space.
You can do it in O(n^2) time and constant space, by using repeated calls to (!!), in principle. In practice you need to be a bit tricky otherwise keeping the reference to the whole list around will stop the GC ever collecting it. You'd need to stream it rather carefully, and then it wouldn't actually be (!!) any more; just something 'like (!!)'. Jules
participants (6)
-
apfelmus
-
David House
-
Evan Laforge
-
Henning Thielemann
-
Jules Bean
-
Sergey Perminov