如何处理haskell中的通用反序列化?

时间:2014-09-25 15:37:46

标签: haskell deserialization

在我的应用程序中,我存储并加载数据库中的对象(当前是本地平面文件......)。这些对象都来自类型系列Event a,也可以是ByteString的可序列化对象。但类型系列中的a可能会有所不同......

这是基类声明:

class BusinessModel a where
  data Event a   :: *
  apply :: a -> Event a -> a

一个示例实现,以及所需的类型:

data User = User { userId :: UserId, userName :: Text } deriving (Eq, Show, Read, Generic)

instance ToJSON User
instance FromJSON User

type UsersView = M.Map UserId User

instance BusinessModel UsersView where

   data Event UsersView = NoEvent              -- ^A no-op event
                       | UserRegistered User
                       deriving (Eq, Show, Read, Generic)

  apply v (UserRegistered u)  = insert (userId u) u v
  apply v _                   = v

以下是我的活动商店的当前界面:

class (MonadIO store) => EventStore store where
  -- store a single event
  store :: Serializable s => s -> store ()
  -- load all events from the store
  load  :: Serializable s => store [s]

然后我们需要能够序列化事件(这里我们只使用Json表示:

instance ToJSON (Event UsersView)
instance FromJSON (Event UsersView)

instance Serializable (Event UsersView) where
  read  = fromJust . decode
  write = encode

我希望能够为所有Event a反序列化所有存储的a个对象,然后将每个Event a应用于包含不同内容的结构中的正确a事件"目标"。当我试图天真地使用load时,我遇到了Serializable多个实例并且无法选择正确实例的麻烦。

在我的脑海中,我可以想到一个简单的解决方案:用适当的a标记每个要阅读的事件,但这看起来不是很优雅?

解决此类问题的最佳方法是什么?

1 个答案:

答案 0 :(得分:2)

在Haskell中确实没有方便的自动方法来实现您的目标。反序列化任意值并通过接口以运行时多态方式使用它们更像是面向对象的模式。

正如您所说,对于序列化和反序列化,您需要以某种方式标记事件以存储和恢复类型信息。 E.g。

data TaggedEvent
    = EventUsersView (Event UsersView)
    | EventSomeOtherView (Event SomeOtherView)
    ...

要删除一些手动样板文件,可以使用模板Haskell自动生成TaggedEvent类型,例如acid-state中的事件。