TL; DR
После прочтения отрывка о постоянстве в книге Окасаки Purely Functional Data Structures и изучения его иллюстративных примеров односвязных списков (именно так реализованы списки Haskell) я задумался. о космических сложностях inits
и tails
Data.List
...
Мне кажется, что
- пространственная сложность
tails
линейна по длине аргумента, и - пространственная сложность
inits
квадратична по длине аргумента,
но простой тест показывает обратное.
Обоснование
С помощью tails
можно поделиться исходным списком. Вычисление tails xs
состоит просто в обходе списка xs
и создании нового указателя на каждый элемент этого списка; нет необходимости воссоздавать часть xs
в памяти.
Напротив, поскольку каждый элемент inits xs
"заканчивается по-разному", такого совместного использования быть не может, и все возможные префиксы xs
должны воссоздаваться в памяти с нуля.
Ориентир
Простой тест ниже показывает, что между двумя функциями нет большой разницы в распределении памяти:
-- Main.hs
import Data.List (inits, tails)
main = do
let intRange = [1 .. 10 ^ 4] :: [Int]
print $ sum intRange
print $ fInits intRange
print $ fTails intRange
fInits :: [Int] -> Int
fInits = sum . map sum . inits
fTails :: [Int] -> Int
fTails = sum . map sum . tails
После компиляции моего файла Main.hs
с помощью
ghc -prof -fprof-auto -O2 -rtsopts Main.hs
и работает
./Main +RTS -p
файл Main.prof
сообщает следующее:
COST CENTRE MODULE %time %alloc
fInits Main 60.1 64.9
fTails Main 39.9 35.0
Память, выделенная для fInits
, и память, выделенная для fTails
, имеют одинаковый порядок величины... Гм...
Что здесь происходит?
- Верны ли мои выводы о пространственной сложности
tails
(линейной) иinits
(квадратичной)? - Если да, то почему GHC выделяет примерно одинаковое количество памяти для
fInits
иfTails
? Имеет ли к этому какое-то отношение слияние списков? - Или мой тест некорректен?
Int
не оптимизируются, поэтомуfTails
также выделяет для них O(n^2). Чтобы проверить это, нужно было бы посмотреть на ядро (у меня нет ghc под рукой). - person   schedule 01.04.2015print $ sum intRange
) перед запускомfInits
илиfTails
. - person Cirdec   schedule 01.04.2015(ಠ_ರ) ?
Используете ли вы тот же тест, что и я? Какую версию GHC вы используете? У меня GHC 7.10.1. - person jub0bs   schedule 01.04.2015+RTS -s
вместо профайлера. - person András Kovács   schedule 01.04.2015100.0%
распределение вfInits
и91.7%
времени, проведенного вfInits
(+RTS -p
, те же параметры компилятора). - person Cirdec   schedule 01.04.2015./Main +RTS -s
? Что вы получите, если воспользуетесь+RTS -p
? - person jub0bs   schedule 01.04.2015+RTS -s
. СRTS -p
я получил результаты, похожие на ваши. - person András Kovács   schedule 01.04.2015inits
иtails
и суммирует. - person András Kovács   schedule 01.04.2015