I need to work with strict and lazy ByteStrings, because this is the requirement preset by the choice of libraries (some mix of happstack, base64, sha256, hexpat, etc.). After some dancing with "fromStrict" and similar I ended up with this:
import qualified Data.ByteString.Char8 as S
import qualified Data.ByteString.Lazy.Char8 as L
class BString s where
lazy :: s -> L.ByteString
strict :: s -> S.ByteString
pack :: String -> s
text :: T.Text -> s
instance BString L.ByteString where
lazy = id
strict = S.concat . L.toChunks
pack = L.pack
text = L.fromStrict . TE.encodeUtf8
instance BString S.ByteString where
lazy = L.fromStrict
strict = id
pack = S.pack
text = TE.encodeUtf8
so that I just put "lazy $" when the library function in hands requires lazy byte string or "strict $" in case of strict version. That works fine, costing an occasional conversion though, but it feels like I've invented bicycle here.
So, the question is if there's a better (shorter, statically typed, more effective) alternative to such code? Is there a library trying to uniform lazy/strict handling? Or maybe I'm doing a wrong thing and it's considered a bad practice (thou shall not convert between lazy and strict or something)?
Thanks.
I would write an adaption layer between your application and these libraries to perform all of the necessary conversions. Design the adaptation layer so that you use your preferred application data types as input and output to those functions.
Once you have chosen your modules the signatures of the library functions are never going to change. That is, you know what kind of string a call to base64 encode will return (by your choice of module.) Therefore, if you need to plumb together two library functions you know exactly what conversions need to be made to fit the two together.