Проблема с вашим "bytesFromPointer" заключается в том, что вы берете упакованное представление StorableArray из pngload и хотите преобразовать его в другое упакованное представление ByteString, проходя через промежуточный список. Иногда лень означает, что промежуточный список не будет создан в памяти, но здесь это не так.
Функция «mapM» является первым нарушителем. Если вы развернете mapM (peekByteOff pointer) [0..(count-1)]
, вы получите
el0 <- peekByteOff pointer 0
el1 <- peekByteOff pointer 1
el2 <- peekByteOff pointer 2
...
eln <- peekByteOff pointer (count-1)
return [el0,el1,el2,...eln]
, поскольку все эти действия происходят в монаде IO, они выполняются по порядку. Это означает, что каждый элемент списка вывода должен быть создан до того, как список будет создан, и лень никогда не сможет вам помочь.
Даже если список был составлен лениво, как отмечает Дон Стюарт, функция «pack» все равно испортит вашу производительность. Проблема с «пакетом» состоит в том, что ему нужно знать, сколько элементов в списке, чтобы выделить правильный объем памяти. Чтобы найти длину списка, программа должна пройти его до конца. Из-за необходимости вычисления длины список должен быть полностью загружен, прежде чем он может быть упакован в строку байтов.
Я считаю "mapM" вместе с "pack" запахом кода. Иногда вы можете заменить «mapM» на «mapM_», но в этом случае лучше использовать функции создания байтовых строк, например, "PackCStringLen".