#haskell
#haskell
Вопрос:
Предположим, у меня есть:
import qualified Data.ByteString.Lazy as L
bs1 :: L.ByteString
bs2 :: L.ByteString
L.append bs1 bs2
Также ленивым в том смысле, что это не приведет к немедленному использованию всего bs1? Аналогично с L.concat
и в отличие L.length
от которого, как я понимаю, это приведет к тому, что он будет использовать всю байтовую строку, потому что ему нужно подсчитать все байты.
Ответ №1:
Простой способ определить, насколько ленива функция, — передать ей частично определенные значения. Например, давайте определим ленивую байтовую строку из одного фрагмента, за которым следует неопределенный хвост.
*Main> let bs1 = L.fromChunks $ B.pack [102, 111, 111] : undefined
*Main> bs1
Chunk "foo" *** Exception: Prelude.undefined
Как вы можете видеть, попытка распечатать его вызывает исключение после первого фрагмента. Теперь давайте определим другую ленивую байтовую строку и попробуем добавить их.
*Main> let bs2 = L.pack [98, 97, 114]
*Main> L.append bs1 bs2
Chunk "foo" *** Exception: Prelude.undefined
L.append
удалось создать первый фрагмент результирующей ленивой байтовой строки. Это означает, что ему нужно было просмотреть только первый фрагмент bs1
для получения первого фрагмента результата, то есть он настолько ленив, насколько вы ожидаете.
Ответ №2:
Да, append и concat являются ленивыми, они будут касаться фрагментов только при необходимости. Первый фрагмент bs1 необходим немедленно, второй (если присутствует), когда первый будет израсходован и т.д.