Strongly typed events in Haskell

纵饮孤独 提交于 2020-01-24 04:11:18

问题


I'm working on my first 'real' Haskell project, and simultaneously trying to get my head around event sourcing. (It seemed like a good match; event sourcing is a rather functional way of looking at data.)

I've hit a wall trying to figure out how to deserialise my events into strongly typed Haskell data. There are two opposing forces at work here:

  1. It shouldn't be possible to apply an event to the wrong type of aggregate. This requirement suggests that I need a separate type of event for each aggregate in my system:

    data PlayerEvent = PlayerCreated Name | NameUpdated Name

    data GameEvent = GameStarted PlayerID PlayerID | MoveMade PlayerID Move

    To use these events you'd use functions with types like applyEvent :: Game -> GameEvent -> Game.

  2. I need to be able to serialise and deserialise between strongly-typed events and JSON objects. This requirement suggests I need polymorphic serialise and deserialise functions:

    class Event e where serialise :: e -> ByteString

    deserialise :: Event e => ByteString -> e

That last deserialise function is the problem. The type signature says that callers can ask for any instance of Event, but of course the type that you get back depends on the ByteString that came in and is determined at run-time.

Here's a stub implementation that won't compile:

deserialise :: Event e => ByteString -> e
deserialise _ = GameStarted 0 0

And the error message:

Could not deduce (e ~ GameEvent)
from the context (Event e)
  bound by the type signature for
             deserialise :: Event e => ByteString -> e
  at ...:20:16-41
  `e' is a rigid type variable bound by
      the type signature for deserialise :: Event e => ByteString -> e
      at ...:20:16
In the return type of a call of `GameStarted'
In the expression: GameStarted 0 0
In an equation for `deserialise':
    deserialise _ = GameStarted 0 0

This sort of thing is straightforward in an object-oriented language with reflection. I find it hard to believe that I've found a problem for which Java's type system is more expressive than Haskell's.

I feel like I must be missing a key abstraction here. What's the correct way to implement the above requirements?


回答1:


If you make deserialize a member of the Event class, then you won't have any problems:

class Event e where
    serialize :: e -> ByteString
    deserialize :: ByteString -> e

instance Event PlayerEvent where
    ...

instance Event GameEvent where
    ...


来源:https://stackoverflow.com/questions/22026038/strongly-typed-events-in-haskell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!