[Haskell-cafe] Too much strictness in binary-0.5.0.2

Alexey Khudyakov alexey.skladnoy at gmail.com
Sun Oct 18 11:53:46 EDT 2009


> Yes. We decided that having the Get monad as a lazy state monad just
> doesn't make sense. It makes this one use case work, but causes more
> problems generally. Certainly we need to be able to do lazy binary
> deserialisation too, but our feeling is that it should be more explicit
> and integrate better with error handling. Using a lazy state monad gives
> us neither.

This is valid point. I think I'll just use variant with explicit laziness.


> Note also that if we changed runGetState to do any error handling that
> this would also break the lazy state monad properties that you were
> previously relying upon.

I'd appreciate addition of error handling very much. Currently I have
to use ErrorT and do checks by hands. I have very simple parsers so
it's possible. It's not possible to do such things in general.

Trading laziness for error handling is good thing I believe. At the
moment it's hard to decode possibly malformed data.


On 10/17/09, Duncan Coutts <duncan.coutts at googlemail.com> wrote:
> On Sat, 2009-09-19 at 00:36 +0400, Khudyakov Alexey wrote:
>> Hello
>>
>> I run into problems with new binary package. Following function reads a
>> list
>> of elements one by one until end of stream. List is very long (won't fit
>> into
>> memory).
>
> Sorry for the late reply.
>
>> In binary-0.5.0.1 and earlier it read list lazily. Now it seems that it
>> tries
>> to read whole list to memory. Program does not produce any output and
>> memory
>> usage steadily grows.
>
> Yes. We decided that having the Get monad as a lazy state monad just
> doesn't make sense. It makes this one use case work, but causes more
> problems generally. Certainly we need to be able to do lazy binary
> deserialisation too, but our feeling is that it should be more explicit
> and integrate better with error handling. Using a lazy state monad gives
> us neither.
>
>> > getStream :: Get a -> Get [a]
>> > getStream getter = do
>> >   empty <- isEmpty
>> >   if empty
>> >     then return []
>> >     else do x <- getter
>> >             xs <- getStream getter
>> >             return (x:xs)
>>
>> How could I add laziness to this function to revert to old behavior.
>
> You can make it explicitly lazy using something like:
>
> getStream :: Get a -> BS.ByteString -> [a]
> getStream getter bs = unfoldr step (bs, 0)
>   where
>     step (bs, off) = case runGetState getOne bs off of
>       (Nothing, _,   _   ) -> Nothing
>       (Just x,  bs', off') -> Just (x, (bs', off'))
>
>     getOne = do
>       empty <- isEmpty
>       if empty
>         then return Nothing
>         else fmap Just getter
>
> Note the distinct lack of error handling, but if we had runGetState
> return an Either then you could still make this code lazy, but you'd
> have to decide what to do when you got a decoding error. You could at
> this point translate it into a pure error, or enrich your output stream
> type to account for the possibility of errors.
>
> Note also that if we changed runGetState to do any error handling that
> this would also break the lazy state monad properties that you were
> previously relying upon.
>
> Duncan
>
>


More information about the Haskell-Cafe mailing list