type Chan = Map.Map Int ByteString.ByteString
is odd looking. Why the duplication? type Chan = Map.Map Int ByteString.ByteString
is odd looking. Why the duplication?let's look at the stdlib `replicate` function. `replicate 5 'x'` gets you `['x', 'x', 'x', 'x', 'x']`. But that's a standard haskell linked list, and there's other list-y things, like ByteString. So there's bytestring module has it's own replicate function which returns a ByteString (like an array afaik) instead of a list.
Now, a bare `import bytestring` just dumps all of the module - its datatypes, its functions - into the global namespace, like a Python `from bytestring import *`, so the two replicate functions are gonna clash. There's a solution - we do `import qualified bytestring`. it behaves like a normal Python `import bytestring`, which means that we have to type `bytestring.replicate` to get that function from earlier. all of the stuff inside the bytestring module is hidden away inside this namespace.
Now, the trouble is, EVERYTHING is hidden away. So, say I want to refer to the actual ByteString datatype, say to write a type signature like: ``` length :: Bytestring a -> Int ``` Now, because of the namespace qualification I did, I actually have to write the verbose ``` length :: bytestring.ByteString a -> Int ``` So that's like saying "bytestring-module.ByteString-datatype" every time you want use a ByteString. that's what the author does, hence the weird duplication you noticed comes from.
The usual solution is: ``` import qualified Data.ByteString as B -- the functions import Data.ByteString (ByteString) -- the datatype ```
which roughly translates to Python as: ``` import bytestring as B from bytestring import ByteString # the ByteString class ```
so now, I can use `B.replicate`, and `ByteString`, which is what I want! Great! But the importing is verbose and, as I said, kinda annoying.
import qualified Data.ByteString as ByteString
import qualified Data.Map.Strict as Map
So everything from “Data.ByteString” has to be prefixed with “ByteString.”In real-world code, depending on conventions, you’d probably add unqualified imports for the type names to avoid the needless duplication:
import Data.ByteString (ByteString)
import Data.Map.Strict (Map)
import qualified Data.ByteString as ByteString
import qualified Data.Map.Strict as Map
type Chan = Map Int ByteString
pushMsg =
…
let inserted = Map.insert … import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByesString.Lazy as BSL
import qualified Data.ByteString.Char8 as BSCThis same can be written as:
type Chan = Map Int ByteString
People do prefer importing Map and ByteString qualified, so their functions will have a prefix of their choice. But very few people import ByteString as "ByteString", most use something shorter.As most things in Haskell, it tends to work greatly. The usual problems go away due to some combination of Haskell's features and the main problems are things you wouldn't think about.