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.