【问题标题】:Strongly typed events in HaskellHaskell 中的强类型事件
【发布时间】:2014-03-28 09:00:02
【问题描述】:

我正在处理我的第一个“真正的”Haskell 项目,同时试图了解event sourcing。 (这似乎是一个很好的匹配;事件溯源是一种查看数据的相当实用的方式。)

我在试图弄清楚如何将我的事件反序列化为强类型 Haskell 数据时遇到了困难。这里有两种相反的力量在起作用:

  1. 不应将事件应用于错误类型的聚合。此要求表明我需要为系统中的每个聚合使用单独类型的事件:

    data PlayerEvent = PlayerCreated Name | NameUpdated Name

    data GameEvent = GameStarted PlayerID PlayerID | MoveMade PlayerID Move

    要使用这些事件,您可以使用类型为 applyEvent :: Game -> GameEvent -> Game 的函数。

  2. 我需要能够在强类型事件和 JSON 对象之间进行序列化和反序列化。这个要求表明我需要多态 serialisedeserialise 函数:

    class Event e where serialise :: e -> ByteString

    deserialise :: Event e => ByteString -> e

最后一个deserialise 函数是问题所在。类型签名表明调用者可以请求Event任何 实例,但当然,您返回的类型取决于传入的ByteString,并在运行时确定。

这是一个无法编译的存根实现:

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

还有错误信息:

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

这种事情在带有反射的面向对象语言中很简单。我很难相信我发现了一个问题,Java 的类型系统比 Haskell 的类型系统更具表现力。

我觉得我必须在这里遗漏一个关键的抽象。实现上述要求的正确方法是什么?

【问题讨论】:

  • 为什么不让deserialize 成为Event 的成员?问题是您说deserialize 可以返回any Event,但您具体说它返回GameEvent。如果它是 Event 类的一部分,那么您将获得所需的多态性。
  • 另外,并不是 Java 的类型系统更具表现力,而是你试图让 Haskell 的类型系统表现得像 Java 的那样,但那是行不通的。
  • @bheklilr 非常感谢。我不知道为什么我一开始没有想到让deserialise 成为Event 的成员。而且,我同意尝试用 Haskell 编写 Java 是一个错误。但是,要从根本上重新连接一个人的大脑仍然很困难!
  • PS 如果你想把它放在一个完整的答案中,我会接受它,十五分将是你的 :)
  • 值得看看这个静态类型的 ES 的 Haskell 实现:gist.github.com/Fristi/7327904,原来的主题是slideshare.net/mobile/chris.e.richardson/…

标签: haskell event-sourcing strong-typing


【解决方案1】:

如果你让deserialize 成为Event 类的成员,那么你不会有任何问题:

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

instance Event PlayerEvent where
    ...

instance Event GameEvent where
    ...

【讨论】:

  • 你不会还有调用者决定调用哪个反序列化实现而不是由字节串的内容决定的核心问题吗?
  • @Ben 是的,但是现在类型类需要反序列化的实现,您可以确定调用者要求的任何类型都将有适当的反序列化实现可用。
猜你喜欢
  • 2010-11-27
  • 1970-01-01
  • 2011-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多