我已声明以下内容
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)
并且希望这可以序列化,因为Qcfg可以写入磁盘或通过网络发送。当我编译它时,我得到错误
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)
我现在还不太确定是否有机会序列化我的TChan,尽管其中的所有单个节点都是show class的成员。
对于TMap
和TPSQ
我想知道是否有办法直接显示TVar
中的值(因为它不会被更改,所以不需要锁定它)无需声明执行readTVar
的实例?
答案 0 :(得分:4)
我理解您的评论意味着您要序列化TVar
的内容而不是TVar
本身。
只有一种方法可以从TVar
中提取值,并且readTVar
:
readTVar :: TVar a -> STM a
...您可以使用IO
在atomically
monad中执行此操作:
atomically . readTVar :: TVar a -> IO a
但是, TChan
更棘手,因为你不能在不清除整个TChan
的情况下检查内容。通过将整个内容作为单个STM
操作进行检查,然后将其全部重新插入,这是可行的,即使是浪费的。如果您选择这样做,最终还是需要在IO
monad中运行。
这意味着您将无法为其派生Show
实例,因为Show
需要纯计算将其转换为String
,而不是一个驻留在IO
中的实例。 Show
monad。
但是,您没有必要使用IO
类。您可以定义一个自定义函数来序列化Show
monad中的数据类型。此外,由于以下情况,通常不建议将PSQ
用于序列化目的:
Read
)没有Read
实例binary
个实例因此,我建议您使用正确的序列化库(如cereal
或IO
)进行序列化和反序列化。这些将数据类型转换为二进制表示,它们使定义编码器和解码器变得非常容易。
但是,即使这些库只接受纯转换的实例而不接受TVar
monad中的操作,所以你必须做的是将序列化分为两个步骤:
IO
monad中提取cereal
的内容。binary
/ Binary
序列化内容(以及其他数据类型)。还有最后一个警告,即并非所有数据类型都有binary
个实例(假设我们使用Binary
包),但幸运的是列表中有toList
个实例,所以方便的解决方法是将数据类型转换为列表(使用fromList
并序列化列表。然后,当您反序列化列表时,使用binary
恢复原始类型
因此,以下函数将完成所有这些操作(使用serializeQcfg file (Qcfg qthresh tdelay cwpsq cwmap cwchan) = do
-- Step 1: Extract contents of concurrency variables
psq <- atomically $ readTVar cwpsq
myMap <- atomically $ readTVar cwmap
myChan <- atomically $ entireTChan cwchan
-- Step 2: Encode the extracted data
encodeFile file (qthresh, tdelay, toList psq, myMap, myChan)
):
serializeQcfg file (Qcfg qthresh tdelay cwpsq cwmap cwchan) = do
-- Step 1: Extract contents of concurrency variables
(psq, myMap, myChain) <- atomically $ (,,) <$> readTVar cwpsq
<*> readTVar cwmap
<*> entireTChan cwchan
-- Step 2: Encode the extracted data
encodeFile file (qthresh, tdelay, toList psq, myMap, myChan)
编辑:实际上,如Daniel指出的那样,将所有原子事务组合成一个事务可能更好,所以你实际上会这样做:
entireTChan
我省略了TChan
的实现,它基本上会刷新entireTChan :: TChan a -> STM [a]
以检查整个内容然后重新加载它,但它的类型签名将是这样的:
binary
我也省略了反序列化实现,但我想如果您理解上面的示例并花时间学习如何使用cereal
或{{1}}包,那么您应该能够解决它很容易。