Polysemy: Design heuristics: Dispatcher
At some point you may have strongly typed effects:
data DocumentsEffects (d :: Type) (m :: Type -> Type) (a :: Type) where
StoreDocument :: d -> DocumentsEffects d m ()
ListDocuments :: DocumentsEffects d m [d]
makeSem ''DocumentsEffects
Sounds nice, until you might want to dynamically dispatch multiples types.
In order to do so, we have to rely on a GADT:
data DocumentType a where
DTLog :: DocumentType Log
DTReciepe :: DocumentType Recipe
DTBill :: DocumentType Bill
Then, we need a dedicated effect:
data AnyDocumentsEffects (m :: Type -> Type) (a :: Type) where
AnyStoreDocument :: DocumentType d -> d -> AnyDocumentsEffects m ()
AnyListDocuments :: DocumentType d -> AnyDocumentsEffects m [d]
makeSem ''AnyDocumentsEffects
Finally, you have to prove that each effect is present:
interpretAnyDocumentsEffects =
interpret $
\case
AnyStoreDocument DTLog x -> storeDocument x
AnyStoreDocument DTReciepe x -> storeDocument x
AnyStoreDocument DTBill x -> storeDocument x
AnyListDocuments DTLog -> listDocuments @Log
AnyListDocuments DTReciepe -> listDocuments @Recipe
AnyListDocuments DTBill -> listDocuments @Bill
See the full the code here.