JSON编码包含MVar的记录

时间:2012-12-07 18:50:41

标签: haskell

假设我有一个记录,其中一个值是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中,以便在更新单个对象时不必阻止整个数据结构。

所以更新操作会像这样进行:

  • 用于获取iObjects散列的实例上的readMVar
  • M.lookup特定商店
  • 在商店上修改MV以进行更新

是否存在比使用这样的嵌套MV更惯用的haskell方法?理想情况下,某种方式可以使MVar远离数据,因此可以保持整个结构的简单。

2 个答案:

答案 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解析/打印可变结构的路径。