I have declared the following
type KEY = (IPv4, Integer)
type TPSQ = TVar (PSQ.PSQ KEY POSIXTime)
type TMap = TVar (Map.Map KEY [String])
data Qcfg = Qcfg { qthresh :: Int, tdelay :: Rational, cwpsq :: TPSQ, cwmap :: TMap, cw
chan :: TChan String } deriving (Show)
and would like this to be serializable in a sense that Qcfg can either be written to disk or be sent over the network. When I compile this I get the error
No instances for (Show TMap, Show TPSQ, Show (TChan String))
arising from the 'deriving' clause of a data type declaration
Possible fix:
add instance declarations for
(Show TMap, Show TPSQ, Show (TChan String))
or use a standalone 'deriving instance' declaration,
so you can specify the instance context yourself
When deriving the instance for (Show Qcfg)
I am now not quite sure whether there is a chance at all to serialize my TChan although all individual nodes in it are members of the show class.
For TMap and TPSQ I wonder whether there are ways to show the values in the TVar directly (because it does not get changed, so there should no need to lock it) without having to declare an instance that does a readTVar ?
I understood your comments to mean that you want to serialize the contents of the
TVarand not theTVaritself.There is only one way to extract the value from a
TVar, and that’sreadTVar:… which you can do in the
IOmonad usingatomically:TChanis more tricky, though, since you can’t inspect the contents without flushing out the entireTChan. This is doable, even if wastefully, by inspecting the entire contents as a singleSTMaction and then reinserting them all. If this is what you choose to do, it would also eventually require being run in theIOmonad.This means you won’t be able to derive a
Showinstance for it, sinceShowexpects a pure computation that converts it to aString, and not one residing in theIOmonad.However, there’s no reason you have to use the
Showclass. You can just define a custom function to serialize your data type in theIOmonad. Also, it’s generally not advisable to useShowfor serialization purposes since:PSQ) have noReadinstanceReadinstances in generalSo I would recommend you use a proper serialization library like
binaryorcerealto do serialization and deserialization. These convert data types to a binary representation, and they make it very easy to define encoders and decoders.However, even those libraries only accept instances for pure conversions and not operations in the
IOmonad, so what you must do is factor your serialization into a two-step process:TVars in theIOmonad.cereal/binary.There is still one last caveat, which is that not all of your data types have
Binaryinstances (assuming we use thebinarypackage), but fortunately lists do have aBinaryinstance, so a convenient work-around is to just convert your data type to a list (usingtoListand serialize the list. Then, when you deserialize the list, you usefromListto recover your original type.So the following function will do all of that (using
binary):Edit: Actually, it’s probably better to combine all the atomic transactions into a single transaction as Daniel pointed out, so you would actually do:
I left out the implementation of
entireTChan, which would basically flush theTChanto inspect the entire contents and then reload it again, but its type signature would be something like:I also left out the deserialization implementation, but I think if you understand the above example and take the time to learn how to use the
binaryorcerealpackages you should be able to figure it out easily enough.