From custom Monad to Polysemy
Previously we have studied a custom Monad
and how to refactor it to make it easier to work with.
For reminder, it was this one:
class Monad m => MyAppMonad m where
getSmtpConfig :: m SmtpConfig
getS3Config :: m S3Config
getRedisParams :: m RedisParams
And it was used as a basis for:
fetchUser :: (MyAppMonad m) => UserName -> m (Maybe User)
storeAvatar :: (MyAppMonad m) => UserId -> ByteString -> m ()
notifySignUp :: (MyAppMonad m) => UserId -> PassCode -> m ()
At some point, we would like to integrate it with a broader Polysemy-based codebase.
A first move to make would be to replace each reader by Polysemy Readers effects:
type MyAppMonadEffects =
'[ Reader SmtpConfig,
Reader S3Config,
Reader RedisParams
]
Then, to avoid any change in the codebase, we have to drop in MyAppMonad
with a fixed EffectsRow:
type MyAppMonad m = m ~ Sem MyAppMonadEffects
And then our getters:
getSmtpConfig :: (Member (Reader SmtpConfig) r) => Sem r SmtpConfig
getSmtpConfig = ask
getS3Config :: (Member (Reader S3Config) r) => Sem r S3Config
getS3Config = ask
getRedisParams :: (Member (Reader RedisParams) r) => Sem r RedisParams
getRedisParams = ask
It's not ideal as effects being fixed dealing with this code (calling/being called by)
would require raise each time effects differ.
But that's a first step, then we can progressively substitute consumers with
Sem r/Members and create individual effects/interpreters.