Deriving via ReaderT
I'm writing the Monad instance for this type using ReaderT and deriving via
newtype HIO a = HIO {runHIO :: Set HiPermission -> IO a}
I've tried to do it this way
newtype HIO a = HIO {runHIO :: Set HiPermission -> IO a}
deriving (Functor, Applicative, Monad) via (ReaderT (Set HiPermission) IO)
but got error:
Couldn't match representation of type `Set HiPermission -> IO c' with that of `ReaderT (Set HiPermission) IO c'
arising from the coercion of the method
What am I doing wrong?
A likely cause of the problem is that you are importing the ReaderT
type, but not the ReaderT
value constructor, that is, the function of type (r -> m a) -> ReaderT r m a
that builds values of type ReaderT
.
For example, you might have written
import Control.Monad.Reader ( ReaderT ) -- only the ReaderT type
instead of
import Control.Monad.Reader -- import everything
or
import Control.Monad.Reader ( ReaderT(..) ) -- import the type and its constuctor
But, why is it necessary for the ReaderT
value constructor to be in scope?
The reason is that DerivingVia
relies on Data.Coerce
under the hood. In the module which defines the instance, we must be able to coerce to the "via" type, in this case ReaderT (Set HiPermission) IO
.
And, as it turns out, to be able to wrap/unwrap a newtype like ReaderT
using coercions, we need to have its value constructor in scope. Quoting from the coerce Haddocks:
The third kind of instance exists for every newtype NT = MkNT T and comes in two variants, namely
instance Coercible a T => Coercible a NT instance Coercible T b => Coercible NT b
This instance is only usable if the constructor MkNT is in scope.