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

ins*_*itu 5 haskell deserialization

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

这是基类声明:

class BusinessModel a where
  data Event a   :: *
  apply :: a -> Event a -> a
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

这是我的事件存储的当前界面:

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]
Run Code Online (Sandbox Code Playgroud)

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

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

instance Serializable (Event UsersView) where
  read  = fromJust . decode
  write = encode
Run Code Online (Sandbox Code Playgroud)

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

从我的头脑中,我可以想到一个简单的解决方案:标记每个要阅读的事件与适当的a相关,但这似乎不是很优雅?

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

sha*_*ang 2

Haskell 中确实没有方便的自动方法来完成您想要做的事情。反序列化任意值并通过接口以运行时多态方式使用它们更像是一种面向对象的模式。

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

data TaggedEvent
    = EventUsersView (Event UsersView)
    | EventSomeOtherView (Event SomeOtherView)
    ...
Run Code Online (Sandbox Code Playgroud)

要删除一些手动样板,TaggedEvent可以使用 Template Haskell 自动生成类型,就像acid-state.