假设我有一个记录,其中一个值是MVar:
data SomeRecord = SomeRecord { frobs :: MVar Integer }
我希望能够使用Aeson从JSON编码/解码它。在编码时,MVar将被解包并且原始值被编码,并且在解码时将发生相反的情况。
能够只编写返回IO (Maybe SomeRecord)
的FromJSON实例和返回IO ByteString
的ToJSON实例会很好,但是因为Parser monad不是MonadIO的实例我不要以为这是可能的。
到目前为止,我已经尝试编写函数来在MVar-encumbered记录和几乎没有MVar类型的相同记录之间进行转换,然后对其进行编码/解码。
我试图找到一些方法让MVar首先保持在我的记录之外。这似乎是理想的。但是假设我出于某种原因无法做到这一点,是否有更简单的方法来处理JSON编码/解码?
修改
我想知道我是否提出了错误的问题。也许我的整个方法都不正确。我要做的是允许一堆连接的客户端(每个在不同的线程上)添加/编辑/删除对象列表。这是类型的样子:
-- the data type for each "room"
data Instance = Instance
{ iName :: T.Text
, iObjects :: M.HashMap T.Text (MVar Store)
...
}
-- the data type for a particular object in the room that can be changed
data Store = Store
{ sObject :: A.Value
...
}
每个“房间”都有Instance
来保存房间对象。实例本身位于MVar中,用于同步iObjects
散列映射的添加/删除,并且每个单独的存储位于MVar中,以便在更新单个对象时不必阻止整个数据结构。
所以更新操作会像这样进行:
是否存在比使用这样的嵌套MV更惯用的haskell方法?理想情况下,某种方式可以使MVar远离数据,因此可以保持整个结构的简单。
答案 0 :(得分:5)
不,你有一个隐藏在纯数据结构中的并发原语。处理起来总是有点尴尬。你将副作用走私到试图接触你的MVar的任何东西。
尝试通过容器为Integer参数化数据类型。 E.g。
data T a = T { frobs :: c Integer }
然后您可以将其实例化为T MVar
,然后进行流式处理,解包,然后以T One
进行操作,其中data One a = One a
。
答案 1 :(得分:0)
FromJSON和ToJSON类型实际上只是在编写解析/打印代码时提供方便。如果我们没有它们,我们仍然可以编写解析器和打印机,它们只需要更多的样板。正如您所发现的那样,这些类型类的制定方式不适用于不纯的值。所以基本上,你坚持使用另一种方法和附带的额外样板。
有一些方法可以让它变得更好。您可以复制FromJSON和ToJSON并修改它们以支持使用monadic IO的解析器和打印机。如果您经常使用这种模式,那可能是值得的。或者,您可以使用unsafePerformIO,虽然这看起来像真的坏主意...甚至可能不值得一提,因为如果您不确切知道自己在做什么,它很容易造成大问题。
当然,就像你提到的那样,你可以尝试让你的结构变得纯净。这对我来说似乎是最好的方法。你可以有另一个具有MVars的结构,然后是一个从不纯的结构中填充纯结构的函数。通过这种方式,纯结构可以作为更容易JSON解析/打印可变结构的路径。