Прошло четыре года с тех пор, как на этот вопрос был дан ответ, но я столкнулся с теми же проблемами, что и gatoatigrado в комментарии к ответу дона Стюарта. Метод put
работает так, как объявлено, но get
читает весь ввод. Я полагаю, что проблема заключается в сопоставлении с шаблоном в операторе case Stream xs <- get
, который должен определить, является ли оставшийся get
значением Stream a
или нет до возврата.
Мое решение использовало пример в Data.Binary.Get в качестве отправной точки:
import Data.ByteString.Lazy(toChunks,ByteString)
import Data.Binary(Binary(..),getWord8)
import Data.Binary.Get(pushChunk,Decoder(..),runGetIncremental)
import Data.List(unfoldr)
decodes :: Binary a => ByteString -> [a]
decodes = runGets (getWord8 >> get)
runGets :: Get a -> ByteString -> [a]
runGets g = unfoldr (decode1 d) . toChunks
where d = runGetIncremental g
decode1 _ [] = Nothing
decode1 d (x:xs) = case d `pushChunk` x of
Fail _ _ str -> error str
Done x' _ a -> Just (a,x':xs)
k@(Partial _) -> decode1 k xs
Обратите внимание на использование getWord8
Это для чтения закодированных []
и :
, полученных в результате определения put
для экземпляра потока. Также обратите внимание, что поскольку getWord8 игнорирует закодированные символы [] и:, эта реализация не обнаружит конец списка. Мой закодированный файл был просто одним списком, так что он работает для этого, но в противном случае вам придется изменить.
В любом случае, этот decodes
работал в постоянной памяти в обоих случаях доступа к голове и последним элементам.