У меня есть следующий фрагмент:
import qualified Data.Vector as V
import qualified Data.ByteString.Lazy as BL
import System.Environment
import Data.Word
import qualified Data.List.Stream as S
histogram :: [Word8] -> V.Vector Int
histogram c = V.accum (+) (V.replicate 256 0) $ S.zip (map fromIntegral c) (S.repeat 1)
mkHistogram file = do
hist <- (histogram . BL.unpack) `fmap` BL.readFile file
print hist
Я вижу это так: Ничего не делается до печати. При печати thunks разворачиваются сначала распаковкой, а затем отображением из Integral по одному Word8 за раз. Каждое из этих word8 заархивировано с 1, опять же по одному значению за раз. Эти кортежи затем принимаются функцией накопителя, которая обновляет массив, по одному кортежу / Word8 за раз. Затем мы переходим к следующему преобразователю и повторяем его до тех пор, пока не кончится содержимое.
Это позволит создавать гистограммы в постоянной памяти, но, увы, этого не происходит, а вместо этого происходит сбой с переполнением стека. Если я попытаюсь профилировать его, я вижу, что он работает до конца, но занимает много памяти (300-500 МБ для файла размером 2,5 МБ). Память получается линейно до конца, пока ее не освободят, образуя «красивый» треугольный граф.
Где мои рассуждения пошли не так, и какие шаги я должен предпринять, чтобы запустить этот запуск в постоянной памяти?