5

In my application I store and load objects from a database (currently a local flat file...). These objects are all from a type family Event a and are also all serialisable to/from ByteString. But the a in the type family can vary...

Here is the base class declaration:

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

And an example implementation, along with needed 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) u v
  apply v _                   = v

Here is the current interface to 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 serialise events (here we simply use the Json representation:

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 deserialise all stored Event a objects, for all a, then apply each Event a to the correct a inside a structure that contains different events "target". When I try to naively use load I run into the trouble of having multiple instances of Serializable and not being able to chose the right one.

Out of the top of my head, I could think of a simple solution: Tag every event to be read with the proper a it pertains to, but this does not seem very elegant?

What is the best approach to this kind of problem?

insitu
  • 4,488
  • 3
  • 25
  • 42
  • 1
    Tag every event with the proper `a`. – John L Sep 25 '14 at 17:20
  • Thanks. Do you have pointers on code/package doing similar things? I guess I am not the first one to implement this. – insitu Sep 25 '14 at 19:54
  • The aeson package does something similar-ish, that might be one place to look. I'm still hoping someone will give a better answer though. – John L Sep 25 '14 at 22:55
  • Can you add a minimal compilable example? Or at least the definition for your type-family and a couple of instances? – shang Sep 26 '14 at 01:33
  • Thanks @shang. Added hopefully relevant part of the code. – insitu Sep 26 '14 at 07:05

1 Answers1

2

There's really no convenient, automatic method in Haskell for what you are trying to do. Deserializing arbitrary values and using them in run-time polymorphic ways via interfaces is more of an object oriented pattern.

As you said yourself, for serialization and deserialization you need to tag the events somehow to store and restore the type information. E.g.

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

To remove some manual boilerplate, the TaggedEvent type could be automatically generated using Template Haskell as is done for example for the events in acid-state.

shang
  • 24,642
  • 3
  • 58
  • 86
  • Thanks for the answer. What would be a proper functional pattern for what I am trying to do? I am implementing some event sourced application where state of application is transient, immutable and modified through events, the latter being the only persistent part of the system. AFAICT, this is typically functional. – insitu Sep 26 '14 at 12:26
  • FWIW, I implemented the tag-based approach which is hinted at in this question: http://stackoverflow.com/questions/26117165/how-to-handle-or-avoid-blockedindefinitelyonstm-exception I had to fiddle a little bit with typing and proper type classes to ensure the views actually have no knowledge of this tag, but it works fine. – insitu Sep 30 '14 at 09:27