I\'m working on a network streaming client that needs to talk to the server. The server encodes the responses in bytestrings, for example, \"1\\NULJohn\\NULTeddy\\NUL501\\NU
You can write your own parser - but there is already a package that can do the parsing for you: cassava and while SO is usually not a place to search for library recommendations, I want to include this answer for people looking for a solution, but not having the time to implement this themselves and looking for a solution that works out of the box.
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
import Data.Csv
import Data.Vector
import Data.ByteString.Lazy as B
import GHC.Generics
data Person = P { personId :: Int
, firstName :: String
, lastName :: String
} deriving (Eq, Generic, Show)
-- the following are provided by friendly neighborhood Generic
instance FromRecord Person
instance ToRecord Person
main :: IO ()
main = do B.writeFile "test" "1\NULThomas\NULof Aquin"
Right thomas <- decodeWith (DecodeOptions 0) NoHeader <$>
B.readFile "test"
print (thomas :: Vector Person)
Basically cassava allows you to parse all X-separated structures into a Vector
, provided you can write down a FromRecord
instance (which needs a parseRecord :: Parser …
function to work.
Side note on Generic
until recently I thought - EVERYTHING - in haskell has a Generic instance, or can derive one. Well this is not the case I wanted to serialize some ThreadId
to CSV/JSON and happened to find out unboxed types are not so easily "genericked"!
And before I forget it - when you speak of streaming and server and so on there is cassava-conduit that might be of help.