[Haskell-cafe] Musings on lists
Viktor Dukhovni
ietf-dane at dukhovni.org
Thu Jul 13 04:39:37 UTC 2023
On Thu, Jul 13, 2023 at 03:39:08PM +1200, Richard O'Keefe wrote:
> 2. xs ++ ys does copy the spine of xs. In a strict language like
> ML or F#, it does so right away. In a non-strict language
> like Haskell, it does so, but later. If you ever explore the
> result of xs ++ ys far enough to reach ys, you will by then
> have copied the spine of xs. This means that xs ++ [a] is still
> more expensive than a : xs, it's just a matter of when the
> payment is made.
Yes, if the list head is used more than once. When "xs ++ ys" is used
in a fold and never seen again, no copying happens, but a thunk is
allocated.
In particular a single list append that's folded away is free, and
the below runs in constant space, regardless of the specified length.
module Main (main) where
import System.Environment
import Data.Foldable
main :: IO ()
main = do
fmap (read . head) getArgs >>= print . sum . xs
where
xs :: Int -> [Int]
xs n = [1..n] ++ [1..n]
The real problem is with, e.g., iterated construction of a list by
appending one element at a time, depth first:
module Main (main) where
import System.Environment
import Data.Foldable
main :: IO ()
main = do
fmap (read . head) getArgs >>= print . sum . xs
where
xs :: Int -> [Int]
xs n = go [] [1..n]
where
go ys [] = ys
go ys (x : xs) = go (ys ++ [x]) xs
The space cost here is at least quadratic:
2 x list length -> 5.1 x allocations
3 x list length -> 12.5 x allocations
4 x list length -> 23 x allocations
...
--
Viktor.
More information about the Haskell-Cafe
mailing list