我正在开发我的第一个“真正的”Haskell项目,同时尝试理解event sourcing。(它似乎很匹配;事件溯源是一种相当函数式的数据处理方式。)
我遇到了一个难题,即如何将我的事件反序列化为强类型的Haskell数据。这里有两股相互对立的力量:
不应该将事件应用于错误类型的聚合根。这个要求表明我需要为系统中的每个聚合根创建一个单独的事件类型:
data PlayerEvent = PlayerCreated Name | NameUpdated Name
data GameEvent = GameStarted PlayerID PlayerID | MoveMade PlayerID Move
要使用这些事件,您可以使用类似于
applyEvent :: Game -> GameEvent -> Game
的函数。我需要能够在强类型事件和JSON对象之间进行序列化和反序列化。这个要求表明我需要多态的
serialise
和deserialise
函数:class Event e where serialise :: e -> ByteString
deserialise :: Event e => ByteString -> e
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
可以返回任何Event
,但是你又明确指出它返回的是一个GameEvent
。如果它是Event
类的一部分,那么你就可以得到所需的多态性。 - bheklilrdeserialise
)作为'事件'(Event
)的成员。并且,我同意尝试在Haskell中编写Java是一个错误。虽然这种思维方式的改变仍然很困难! - Benjamin Hodgson