0

假设我有一个记录,其中一个值为 MVar:

data SomeRecord = SomeRecord { frobs :: MVar Integer }

我希望能够使用 Aeson 从 JSON 编码/解码它。编码时,MVar 将被解包并编码原始值,而解码时会发生相反的情况。

能够编写一个返回 anIO (Maybe SomeRecord)的 FromJSON 实例和一个返回 an 的 ToJSON 实例会很好IO ByteString,但是由于 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保存房间对象的对象。Instance 本身在一个 MVar 中以同步iObjectshashmap 的添加/删除,并且每个单独的存储都在一个 MVar 中,以便在更新单个对象时整个数据结构不必阻塞。

因此更新操作如下进行:

  • 实例上的 readMVar 以获取 iObjects 哈希
  • M.查找特定商店
  • 在 store 上 modifyMVar 进行更新

有没有比使用这样的嵌套 MVar 更惯用的 Haskell 方法?理想情况下,某种使 MVar 远离数据的方法,因此持久化整个结构会很简单。

4

2 回答 2

5

不,您有一个隐藏在纯数据结构中的并发原语。处理起来总是有点尴尬。您正在将副作用走私到任何试图触及您的 MVar 的东西中。

尝试通过 Integer 的容器参数化数据类型。例如

data T a = T { frobs :: c Integer }

然后你可以对它进行实例化T MVar,对于流式传输,解包,然后将其作为T One, where进行操作data One a = One a

于 2012-12-07T19:08:23.570 回答
0

FromJSON 和 ToJSON 类型类实际上只是为了在编写解析/打印代码时提供便利。如果我们没有它们,我们仍然可以编写解析器和打印机,它们只是需要更多样板。正如您所发现的,这些类型类的制定方式并不适用于不纯的值。所以基本上,你被另一种方法和随之而来的额外样板所困。

有几个选项可以让它变得更好。您可以复制 FromJSON 和 ToJSON 并修改它们以支持使用 monadic IO 的解析器和打印机。如果你经常使用这种模式,那可能是值得的。或者,您可以使用 unsafePerformIO,尽管这似乎是一个非常糟糕的主意……甚至可能不值得一提,因为如果您不确切知道自己在做什么,它很容易导致大问题。

当然,就像您提到的那样,您可以尝试使您的结构纯净。这对我来说似乎是最好的方法。您可以拥有另一个具有 MVar 的结构,然后是一个从不纯结构填充纯结构的函数。以这种方式,纯结构充当更容易 JSON 解析/打印可变结构的路径。

于 2012-12-07T19:06:45.503 回答