Eventos fortemente digitados em Haskell
-
21-12-2019 - |
Pergunta
Estou trabalhando em meu primeiro projeto Haskell 'real' e, ao mesmo tempo, tentando entender fornecimento de eventos.(Pareceu uma boa combinação;a fonte de eventos é uma forma bastante funcional de analisar os dados.)
Eu bati em uma parede tentando descobrir como desserializar meus eventos em dados Haskell fortemente digitados.Existem duas forças opostas em ação aqui:
Não deveria ser possível aplicar um evento ao tipo errado de agregação.Este requisito sugere que preciso de um tipo de evento separado para cada agregado no meu sistema:
data PlayerEvent = PlayerCreated Name | NameUpdated Name
data GameEvent = GameStarted PlayerID PlayerID | MoveMade PlayerID Move
Para usar esses eventos você usaria funções com tipos como
applyEvent :: Game -> GameEvent -> Game
.Preciso ser capaz de serializar e desserializar entre eventos fortemente digitados e objetos JSON.Este requisito sugere que preciso de polimórfico
serialise
edeserialise
funções:class Event e where serialise :: e -> ByteString
deserialise :: Event e => ByteString -> e
Esse último deserialise
função é o problema.A assinatura de tipo diz que os chamadores podem solicitar qualquer instancia de Event
, mas é claro que o tipo que você recebe depende do ByteString
que entrou e é determinado em tempo de execução.
Aqui está uma implementação de stub que não será compilada:
deserialise :: Event e => ByteString -> e
deserialise _ = GameStarted 0 0
E a mensagem de erro:
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
Esse tipo de coisa é simples em uma linguagem orientada a objetos com reflexão.Acho difícil acreditar que encontrei um problema para o qual o sistema de tipos Java é mais expressivo que o de Haskell.
Sinto que devo estar perdendo uma abstração importante aqui.Qual é a maneira correta de implementar os requisitos acima?
Solução
Se você fizer deserialize
um membro do Event
class, então você não terá problemas:
class Event e where
serialize :: e -> ByteString
deserialize :: ByteString -> e
instance Event PlayerEvent where
...
instance Event GameEvent where
...