Yes, you can make your record definitions polymorphic on the effect monad, and only commit to a concrete monad in the constructor. Or not even then: you can make your constructors work for any MonadUnliftIO
for example. A ReaderT
is often used to carry request-scoped values. The subject is discussed in this other thread.
But here I wanted to make the components (“beans”) themselves very plain and simple in that respect. No polymorphism, no MonadUnliftIO
, no ReaderT
. Just IO
.
btw, I like the idea in the code you linked of defining hoist
-like functions for domain records:
hoist :: (forall a. m a -> n a) -> QuestionnaireRepository m -> QuestionnaireRepository n
They make it easy to implement decorators. More sophisticated ones could even receive the field (the “method”) name in the callback. Such hoist
functions can be defined (admittedly, in a less flexible way) for records that work monomorphically in IO
.