singleton 'a' `mappend` (singleton 'b' `mappend` singleton 'c')to
singleton 'a' `mappend` singleton 'b' `mappend` singleton 'c'as the latter associates mappend to the left.
singleton 'a' `mappend` (singleton 'b' `mappend` singleton 'c')to
singleton 'a' `mappend` singleton 'b' `mappend` singleton 'c'as the latter associates mappend to the left. Or, equivalently, prefer
singleton 'a' <> singleton 'b' <> singleton 'c'since the <> from recent versions of Monoid associates to the right.
import Blaze.ByteString.BuilderIt provides you with a type Builder that allows to efficiently construct lazy bytestrings with a large average chunk size. Intuitively, a Builder denotes the construction of a part of a lazy bytestring. Builders can either be created using one of the primitive combinators in Blaze.ByteString.Builder.Write or by using one of the predefined combinators for standard Haskell values (see the exposed modules of this package). Concatenation of builders is done using mappend from the Monoid typeclass. Here is a small example that serializes a list of strings using the UTF-8 encoding.
import Blaze.ByteString.Builder.Char.Utf8
strings :: [String] strings = replicate 10000 "Hello there!"The function fromString creates a Builder denoting the UTF-8 encoded argument. Hence, UTF-8 encoding and concatenating all strings can be done follows.
concatenation :: Builder concatenation = mconcat $ map fromString stringsThe function toLazyByteString can be used to execute a Builder and obtain the resulting lazy bytestring.
result :: L.ByteString result = toLazyByteString concatenationThe result is a lazy bytestring containing 10000 repetitions of the string "Hello there!" encoded using UTF-8. The corresponding 120000 bytes are distributed among three chunks of 32kb and a last chunk of 6kb. A note on history. This serialization library was inspired by the Data.Binary.Builder module provided by the binary package. It was originally developed with the specific needs of the blaze-html package in mind. Since then it has been restructured to serve as a drop-in replacement for Data.Binary.Builder, which it improves upon both in speed as well as expressivity.
someOutputStream :: OutputStream ByteStringYou create a new output stream wrapping the original one that accepts Builder values:
do newStream <- Streams.builderStream someOutputStream Streams.write (Just $ byteString "hello") newStream ....You can flush the output buffer using flush:
.... Streams.write (Just flush) newStream ....As a convention, builderStream will write the empty string to the wrapped OutputStream upon a builder buffer flush. Output streams which receive ByteString should either ignore the empty string or interpret it as a signal to flush their own buffers, as the handleToOutputStream and System.IO.Streams.Zlib functions do. Example
example :: IO [ByteString] example = do let l1 = intersperse " " ["the", "quick", "brown", "fox"] let l2 = intersperse " " ["jumped", "over", "the"] let l = map byteString l1 ++ [flush] ++ map byteString l2 is <- Streams.fromList l (os0, grab) <- Streams.listOutputStream os <- Streams.builderStream os0 Streams.connect is os >> grab ghci> example ["the quick brown fox","","jumped over the"]
import Text.Pandoc.Builder myDoc :: Pandoc myDoc = setTitle "My title" $ doc $ para "This is the first paragraph" <> para ("And " <> emph "another" <> ".") <> bulletList [ para "item one" <> para "continuation" , plain ("item two and a " <> link "/url" "go to url" "link") ]Isn't that nicer than writing the following?
import Text.Pandoc.Definition import Data.Map (fromList) myDoc :: Pandoc myDoc = Pandoc (Meta {unMeta = fromList [("title", MetaInlines [Str "My",Space,Str "title"])]}) [Para [Str "This",Space,Str "is",Space,Str "the",Space,Str "first", Space,Str "paragraph"],Para [Str "And",Space,Emph [Str "another"], Str "."] ,BulletList [ [Para [Str "item",Space,Str "one"] ,Para [Str "continuation"]] ,[Plain [Str "item",Space,Str "two",Space,Str "and",Space, Str "a",Space,Link nullAttr [Str "link"] ("/url","go to url")]]]]And of course, you can use Haskell to define your own builders:
import Text.Pandoc.Builder import Text.JSON import Control.Arrow ((***)) import Data.Monoid (mempty) -- | Converts a JSON document into 'Blocks'. json :: String -> Blocks json x = case decode x of Ok y -> jsValueToBlocks y Error y -> error y where jsValueToBlocks x = case x of JSNull -> mempty JSBool x -> plain $ text $ show x JSRational _ x -> plain $ text $ show x JSString x -> plain $ text $ fromJSString x JSArray xs -> bulletList $ map jsValueToBlocks xs JSObject x -> definitionList $ map (text *** (:[]) . jsValueToBlocks) $ fromJSObject x