How to handle general deserialization in haskell?

In my application, I store and load objects from the database (currently it is a local flat file ...). All of these objects belong to the Event a type family and can also be serialized to / from ByteString . But a in the type family can change ...

Here is the base class declaration:

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

And an example implementation, as well as the necessary types:

 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) uv apply v _ = v 

Here is the current interface for my event store:

 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] 

Then we need to be able to serialize events (here we just use the Json view:

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

I would like to be able to deserialize all stored Event a objects for all a , and then apply each Event a to the correct a inside a structure containing different β€œtarget” events. When I try to naively use load , I run into the problem of having multiple instances of Serializable and are not able to choose the right one.

From the top of my head, I could think of a simple solution: mark each event that needs to be read with the corresponding a to which it refers, but it does not seem very elegant?

What is the best approach to this problem?

+5
source share
1 answer

Haskell really does not have a convenient automatic method for what you are trying to do. The deserialization of arbitrary values ​​and their use during polymorphic methods through interfaces is more likely an object-oriented pattern.

As you said yourself, for serialization and deserialization you need to somehow mark events for storing and restoring type information. For instance.

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

To remove a manual template, the TaggedEvent type can be automatically generated using the Haskell template, as is done, for example, for acid-state events.

+2
source

Source: https://habr.com/ru/post/1203410/


All Articles