[Haskell-cafe] question about PutM patterns

Alexander V Vershilov alexander.vershilov at gmail.com
Sat Mar 23 06:35:05 CET 2013

Hello, cafe.

I have a big problem using builders, so currently I'm using own
builder based on Nettle one [1].
It uses Strict bytestring to build into and unchecked writes, thus
it's very unsafe, plus other
builders/PutM, developed rapidly so I like to switch to another one.
However I use some patterns that seems not implemented in other
builders, so I'd like to hear
advices how to implement it there or how I can write code without using them.
All of the patterns is done in order to have more performance and
gives a way to build complex
data without additional allocations.

1). Delayed input:
This unsafe pattern can be implemented in any PutM monad for any
constant sized value,
the idea is that we write a plaseholder and returns a funtion that
will write correct value to the
address when applied. This pattern is needed when we need to update
length or CRC sum after
content is written:

> test1 put = delayedWord16be >>= \ph -> someOtherStuff >> undelay ph calculateCRC

2). LookAhead:
Sometimes I need to know the length of the content to be written,
possibly I can write content
to ByteString, and calculate length and write it, however if resulting
type is not LBS it leads to
additional allocations and memory move. For PutM a special wrapper can
be written
withLength :: a {- length type -} -> PutM () -> PutM ().
Or special data structure and delayed input can be used, special data
structure is Marker, it
marks a place in datastructure allowing to calculate distances, it
works very efficiently with
ByteString, but I have no idea how to implement it with LBS:

> test1 put =  delayedWord32be >>= \ph -> marker -> \m -> put >> distance m >>= undelay . fromIntegral

3). LookBehind
Returning back to crc calculation I had to use additional pattern,
it's a lookback: I need to inspect
unfinished data, that I've already have written, I have not done
correct wrappers so I've used markers
and fromForeignPtr from ByteString.Internal:

> test3 = do
>    m <- marker
>    somestuff
>    d <- distance marker
>    let crc =  (unsafePerformIO $ BS.unsafePackAddressLen hlen' (toAddr m))


More information about the Haskell-Cafe mailing list