Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
This module differs from the Data.ByteString.Builder module by writing the octets in reverse order, which lets us compute the length of a submessage by writing that submessage and measuring its length before we write a variadic integer prefix encoding that length.
Example use:
>>>
Data.ByteString.Lazy.unpack (toLazyByteString (withLengthOf (word64Base128LEVar . fromIntegral) (word32BE 42 <> charUtf8 'λ')))
[6,0,0,0,42,206,187]
Synopsis
- data BuildR
- etaBuildR :: (a -> BuildR) -> a -> BuildR
- ensure :: Int -> BuildR -> BuildR
- withLengthOf :: (Int -> BuildR) -> BuildR -> BuildR
- byteString :: ByteString -> BuildR
- lazyByteString :: ByteString -> BuildR
- shortByteString :: ShortByteString -> BuildR
- word8 :: Word8 -> BuildR
- int8 :: Int8 -> BuildR
- word16BE :: Word16 -> BuildR
- word16LE :: Word16 -> BuildR
- int16BE :: Int16 -> BuildR
- int16LE :: Int16 -> BuildR
- word32BE :: Word32 -> BuildR
- word32LE :: Word32 -> BuildR
- int32BE :: Int32 -> BuildR
- int32LE :: Int32 -> BuildR
- word64BE :: Word64 -> BuildR
- word64LE :: Word64 -> BuildR
- int64BE :: Int64 -> BuildR
- int64LE :: Int64 -> BuildR
- floatBE :: Float -> BuildR
- floatLE :: Float -> BuildR
- doubleBE :: Double -> BuildR
- doubleLE :: Double -> BuildR
- char7 :: Char -> BuildR
- string7 :: String -> BuildR
- char8 :: Char -> BuildR
- string8 :: String -> BuildR
- charUtf8 :: Char -> BuildR
- stringUtf8 :: String -> BuildR
- textUtf8 :: Text -> BuildR
- lazyTextUtf8 :: Text -> BuildR
- shortTextUtf8 :: ShortText -> BuildR
- wordBase128LEVar :: Word -> BuildR
- wordBase128LEVar_inline :: Word -> BuildR
- word32Base128LEVar :: Word32 -> BuildR
- word32Base128LEVar_inline :: Word32 -> BuildR
- word64Base128LEVar :: Word64 -> BuildR
- word64Base128LEVar_inline :: Word64 -> BuildR
- vectorBuildR :: Vector v a => (a -> BuildR) -> v a -> BuildR
- runBuildR :: BuildR -> (Int, ByteString)
- toLazyByteString :: BuildR -> ByteString
- foldlRVector :: Vector v a => (b -> a -> b) -> b -> v a -> b
- testWithUnused :: (Int -> BuildR) -> BuildR
BuildR
type
Writes bytes in reverse order, updating the current state.
It is the responsibility of the execution context and buffer
management primitives to ensure that the current buffer remains
reachable during builder execution, though completed buffers
may be copied to new storage at any time. Aside from those
primitives, BuildR
implementations may ignore that issue.
When combining BuildR
s with <>
we expect the best performance
when associating to the left. For example
,
though unless your foldl
(<>
) mempty
foldl
iteration starts from the right there may
still be issues. Consider using vectorBuildR
instead of foldMap
.
Create BuildR
s
etaBuildR :: (a -> BuildR) -> a -> BuildR Source #
Eta-expands a function that produces a BuildR
, so that
its input is not evaluated until the builder state is presented.
This odd combinator seems to help performance at times, though
it may change behavior on nonterminating values of type a
.
ensure :: Int -> BuildR -> BuildR Source #
Ensures that the current buffer has at least the given number of bytes before executing the given builder.
withLengthOf :: (Int -> BuildR) -> BuildR -> BuildR Source #
Executes the right builder, measuring how many bytes it writes, then provides that figure to the left builder.
byteString :: ByteString -> BuildR Source #
Convert a strict ByteString
to a BuildR
byteString (x <> y) = byteString x <> byteString y byteString mempty = mempty
>>>
byteString "ABC"
Proto3.Wire.Reverse.lazyByteString "ABC"
lazyByteString :: ByteString -> BuildR Source #
Convert a lazy ByteString
to a BuildR
Warning: evaluating the length will force the lazy ByteString
's chunks,
and they will remain allocated until you finish using the builder.
lazyByteString (x <> y) = lazyByteString x <> lazyByteString y lazyByteString mempty = mempty
lazyByteString . toLazyByteString = id toLazyByteString . lazyByteString = id
>>>
lazyByteString "ABC"
Proto3.Wire.Reverse.lazyByteString "ABC"
shortByteString :: ShortByteString -> BuildR Source #
Convert a ShortByteString
to a BuildR
shortByteString (x <> y) = shortByteString x <> shortByteString y shortByteString mempty = mempty
>>>
shortByteString "ABC"
Proto3.Wire.Reverse.lazyByteString "ABC"
string7 :: String -> BuildR Source #
Convert an ASCII
String
to a BuildR
Careful: If you provide a Unicode String
that has non-ASCII
characters then this will only encode the lowest 7 bits of each character
string7 (x <> y) = string7 x <> string7 y string7 mempty = mempty
>>>
string7 "ABC"
Proto3.Wire.Reverse.lazyByteString "ABC">>>
string7 "←↑→↓" -- Example of truncation
Proto3.Wire.Reverse.lazyByteString "\DLE\DC1\DC2\DC3"
char8 :: Char -> BuildR Source #
Convert an ISO/IEC 8859-1
Char
to a BuildR
Careful: If you provide a Unicode character that is not part of the
ISO/IEC 8859-1
alphabet then this will only encode the lowest 8 bits
>>>
char8 ';'
Proto3.Wire.Reverse.lazyByteString ";">>>
char8 'λ' -- Example of truncation
Proto3.Wire.Reverse.lazyByteString "\187"
string8 :: String -> BuildR Source #
Convert an ISO/IEC 8859-1
String
to a BuildR
Careful: If you provide a Unicode String
that has non-ISO/IEC 8859-1
characters then this will only encode the lowest 8 bits of each character
string8 (x <> y) = string8 x <> string8 y string8 mempty = mempty
>>>
string8 "ABC"
Proto3.Wire.Reverse.lazyByteString "ABC">>>
string8 "←↑→↓" -- Example of truncation
Proto3.Wire.Reverse.lazyByteString "\144\145\146\147"
charUtf8 :: Char -> BuildR Source #
Convert a Unicode Char
to a BuildR
using a UTF-8
encoding
>>>
charUtf8 'A'
Proto3.Wire.Reverse.lazyByteString "A">>>
charUtf8 'λ'
Proto3.Wire.Reverse.lazyByteString "\206\187">>>
charUtf8 (Data.Char.chr 0x7FF)
Proto3.Wire.Reverse.lazyByteString "\223\191">>>
charUtf8 (Data.Char.chr 0x800)
Proto3.Wire.Reverse.lazyByteString "\224\160\128">>>
charUtf8 (Data.Char.chr 0xFFFF)
Proto3.Wire.Reverse.lazyByteString "\239\191\191">>>
charUtf8 (Data.Char.chr 0x10000)
Proto3.Wire.Reverse.lazyByteString "\240\144\128\128">>>
charUtf8 (Data.Char.chr 0x10FFFF)
Proto3.Wire.Reverse.lazyByteString "\244\143\191\191"
stringUtf8 :: String -> BuildR Source #
Convert a Unicode String
to a BuildR
using a UTF-8
encoding
stringUtf8 (x <> y) = stringUtf8 x <> stringUtf8 y stringUtf8 mempty = mempty
>>>
stringUtf8 "ABC"
Proto3.Wire.Reverse.lazyByteString "ABC">>>
stringUtf8 "←↑→↓"
Proto3.Wire.Reverse.lazyByteString "\226\134\144\226\134\145\226\134\146\226\134\147">>>
Data.ByteString.Lazy.hPutStr System.IO.stdout (toLazyByteString (stringUtf8 "←↑→↓\n"))
←↑→↓
lazyTextUtf8 :: Text -> BuildR Source #
Convert a Unicode lazy Text
to a BuildR
using a UTF-8
encoding
lazyTextUtf8 (x <> y) = lazyTextUtf8 x <> lazyTextUtf8 y lazyTextUtf8 mempty = mempty
>>>
lazyTextUtf8 "ABC"
Proto3.Wire.Reverse.lazyByteString "ABC">>>
lazyTextUtf8 "←↑→↓"
Proto3.Wire.Reverse.lazyByteString "\226\134\144\226\134\145\226\134\146\226\134\147"
shortTextUtf8 :: ShortText -> BuildR Source #
Convert a ShortText
to a BuildR
using a UTF-8
encoding.
shortTextUtf8 (x <> y) = shortTextUtf8 x <> shortTextUtf8 y shortTextUtf8 mempty = mempty
>>>
shortTextUtf8 "ABC"
Proto3.Wire.Reverse.lazyByteString "ABC">>>
shortTextUtf8 "←↑→↓"
Proto3.Wire.Reverse.lazyByteString "\226\134\144\226\134\145\226\134\146\226\134\147"
wordBase128LEVar :: Word -> BuildR Source #
Convert a Word
to a BuildR
using this variable-length encoding:
- Convert the given value to a base 128 representation without unnecessary digits (that is, omit zero digits unless they are less significant than nonzero digits).
- Present those base-128 digits in order of increasing significance (that is, in little-endian order).
- Add 128 to every digit except the most significant digit, yielding a sequence of octets terminated by one that is <= 127.
This encoding is used in the wire format of Protocol Buffers version 3.
>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar 42))
[42]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar 5376))
[128,42]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar (Data.Bits.shiftL 1 7 - 1)))
[127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar (Data.Bits.shiftL 1 7)))
[128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar (Data.Bits.shiftL 1 14 - 1)))
[255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar (Data.Bits.shiftL 1 14)))
[128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar (Data.Bits.shiftL 1 21 - 1)))
[255,255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar (Data.Bits.shiftL 1 21)))
[128,128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar (Data.Bits.shiftL 1 28 - 1)))
[255,255,255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar (Data.Bits.shiftL 1 28)))
[128,128,128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar (Data.Bits.shiftL 1 32 - 1)))
[255,255,255,255,15]
wordBase128LEVar_inline :: Word -> BuildR Source #
Like wordBase128LEVar
but inlined, which may bloat your code. On
the other hand, inlining an application to a constant may shrink your code.
>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar_inline 42))
[42]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar_inline 5376))
[128,42]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar_inline (Data.Bits.shiftL 1 7 - 1)))
[127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar_inline (Data.Bits.shiftL 1 7)))
[128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar_inline (Data.Bits.shiftL 1 14 - 1)))
[255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar_inline (Data.Bits.shiftL 1 14)))
[128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar_inline (Data.Bits.shiftL 1 21 - 1)))
[255,255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar_inline (Data.Bits.shiftL 1 21)))
[128,128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar_inline (Data.Bits.shiftL 1 28 - 1)))
[255,255,255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar_inline (Data.Bits.shiftL 1 28)))
[128,128,128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (wordBase128LEVar_inline (Data.Bits.shiftL 1 32 - 1)))
[255,255,255,255,15]
word32Base128LEVar :: Word32 -> BuildR Source #
Convert a Word32
to a BuildR
using this variable-length encoding:
- Convert the given value to a base 128 representation without unnecessary digits (that is, omit zero digits unless they are less significant than nonzero digits).
- Present those base-128 digits in order of increasing significance (that is, in little-endian order).
- Add 128 to every digit except the most significant digit, yielding a sequence of octets terminated by one that is <= 127.
This encoding is used in the wire format of Protocol Buffers version 3.
>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar 42))
[42]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar 5376))
[128,42]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar (Data.Bits.shiftL 1 7 - 1)))
[127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar (Data.Bits.shiftL 1 7)))
[128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar (Data.Bits.shiftL 1 14 - 1)))
[255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar (Data.Bits.shiftL 1 14)))
[128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar (Data.Bits.shiftL 1 21 - 1)))
[255,255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar (Data.Bits.shiftL 1 21)))
[128,128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar (Data.Bits.shiftL 1 28 - 1)))
[255,255,255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar (Data.Bits.shiftL 1 28)))
[128,128,128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar (Data.Bits.shiftL 1 32 - 1)))
[255,255,255,255,15]
word32Base128LEVar_inline :: Word32 -> BuildR Source #
Like word32Base128LEVar
but inlined, which may bloat your code. On
the other hand, inlining an application to a constant may shrink your code.
Currently word32Base128LEVar
is fully inline, so this makes no difference,
but in future we might make different default space/speed tradeoffs.
>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar_inline 42))
[42]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar_inline 5376))
[128,42]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar_inline (Data.Bits.shiftL 1 7 - 1)))
[127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar_inline (Data.Bits.shiftL 1 7)))
[128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar_inline (Data.Bits.shiftL 1 14 - 1)))
[255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar_inline (Data.Bits.shiftL 1 14)))
[128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar_inline (Data.Bits.shiftL 1 21 - 1)))
[255,255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar_inline (Data.Bits.shiftL 1 21)))
[128,128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar_inline (Data.Bits.shiftL 1 28 - 1)))
[255,255,255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar_inline (Data.Bits.shiftL 1 28)))
[128,128,128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word32Base128LEVar_inline (Data.Bits.shiftL 1 32 - 1)))
[255,255,255,255,15]
word64Base128LEVar :: Word64 -> BuildR Source #
Like word32Base128LEVar
but for 64-bit inputs.
Inlines when the value fits within 32 bits, but see
also word64Base128LEVar_inline
, which always inlines.
>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar 42))
[42]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar 5376))
[128,42]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar (Data.Bits.shiftL 1 7 - 1)))
[127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar (Data.Bits.shiftL 1 7)))
[128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar (Data.Bits.shiftL 1 14 - 1)))
[255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar (Data.Bits.shiftL 1 14)))
[128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar (Data.Bits.shiftL 1 21 - 1)))
[255,255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar (Data.Bits.shiftL 1 21)))
[128,128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar (Data.Bits.shiftL 1 28 - 1)))
[255,255,255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar (Data.Bits.shiftL 1 28)))
[128,128,128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar (Data.Bits.shiftL 1 32 - 1)))
[255,255,255,255,15]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar (Data.Bits.shiftL 1 32)))
[128,128,128,128,16]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar (Data.Bits.shiftL 1 56 - 1)))
[255,255,255,255,255,255,255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar (Data.Bits.shiftL 1 56)))
[128,128,128,128,128,128,128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar (Data.Bits.shiftL 1 60 - 1)))
[255,255,255,255,255,255,255,255,15]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar (Data.Bits.shiftL 1 60)))
[128,128,128,128,128,128,128,128,16]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar (Data.Bits.shiftL 1 63 - 1)))
[255,255,255,255,255,255,255,255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar (Data.Bits.shiftL 1 63)))
[128,128,128,128,128,128,128,128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar (- (1 :: Data.Word.Word64))))
[255,255,255,255,255,255,255,255,255,1]
word64Base128LEVar_inline :: Word64 -> BuildR Source #
Like word64Base128LEVar
but inlined, which may bloat your code. On
the other hand, inlining an application to a constant may shrink your code.
>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline 42))
[42]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline 5376))
[128,42]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline (Data.Bits.shiftL 1 7 - 1)))
[127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline (Data.Bits.shiftL 1 7)))
[128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline (Data.Bits.shiftL 1 14 - 1)))
[255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline (Data.Bits.shiftL 1 14)))
[128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline (Data.Bits.shiftL 1 21 - 1)))
[255,255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline (Data.Bits.shiftL 1 21)))
[128,128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline (Data.Bits.shiftL 1 28 - 1)))
[255,255,255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline (Data.Bits.shiftL 1 28)))
[128,128,128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline (Data.Bits.shiftL 1 32 - 1)))
[255,255,255,255,15]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline (Data.Bits.shiftL 1 32)))
[128,128,128,128,16]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline (Data.Bits.shiftL 1 56 - 1)))
[255,255,255,255,255,255,255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline (Data.Bits.shiftL 1 56)))
[128,128,128,128,128,128,128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline (Data.Bits.shiftL 1 60 - 1)))
[255,255,255,255,255,255,255,255,15]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline (Data.Bits.shiftL 1 60)))
[128,128,128,128,128,128,128,128,16]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline (Data.Bits.shiftL 1 63 - 1)))
[255,255,255,255,255,255,255,255,127]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline (Data.Bits.shiftL 1 63)))
[128,128,128,128,128,128,128,128,128,1]>>>
Data.ByteString.Lazy.unpack (toLazyByteString (word64Base128LEVar_inline (- (1 :: Data.Word.Word64))))
[255,255,255,255,255,255,255,255,255,1]
vectorBuildR :: Vector v a => (a -> BuildR) -> v a -> BuildR Source #
Essentially foldMap
, but iterates right to left for efficiency.
Consume BuildR
s
runBuildR :: BuildR -> (Int, ByteString) Source #
Like toLazyByteString
but also
returns the total length of the lazy ByteString
,
which is computed as a side effect of encoding.
toLazyByteString :: BuildR -> ByteString Source #
Create a lazy ByteString
from a BuildR
toLazyByteString (x <> y) = toLazyByteString x <> toLazyByteString y toLazyByteString mempty = mempty
>>>
toLazyByteString (stringUtf8 "ABC")
"ABC"
Helpful combinators
foldlRVector :: Vector v a => (b -> a -> b) -> b -> v a -> b Source #
Like foldl
but iterates right-to-left, which
is often useful when creating reverse builders.