3
votes

I'm trying to make an instance of MonadIO for a type that represents computations in the cloud. So liftIO would represent an IO action that is executed locally.

transient-universe, the library that provides this, provides a function localIO that does exactly this. But it is not composable in some other library that could embed any other MonadIO.

The problem is, that localIO requires the return type of the IO action to be an instance of Read, Show and Typeable. Whereas MonadIO doesn't contemplate this case:

class MonadIO m where
    liftIO :: IO a -> m a

In my case, I'd need to write another type class, that does it:

class RestrictableMonadIO (m a) where
    liftRestrictedIO :: IO a -> m a

So it would allow me to do this:

instance (Read a, Show a, Typeable a) => MonadIO (Cloud a) where
    liftRestrictedIO = localIO

Is there a way of doing this without having to declare my own typeclass?

I don't think this is possible. It is well-known that the standard functor, monad etc. classes don't cope well with additional constraints. Data.Set should be a functor, but it is not because of the Ord constraint, for instance. Some more advanced classes have been proposed, like indexed monads, to address this issue, but they never became really popular.chi
@chi Can you elaborate on indexed monads being used to add extra class constraints?gallais
@gallais class IxMonad m a b where (>>=) :: m a -> (a->m b) -> m b allows for instance IxMonad [] a b and instance (Ord a, Ord b) => IxMonad Data.Set a b. Or, class CMonad m (c :: * -> Constraint) where (>>=) :: (c a, c b) => ... allows for an additional constraint. (I am probably using the term "indexed monad" here a bit loosely, but you get the idea)chi
Oh okay, so not indexed monads? Your definition looks pretty dodgy though: you'd be able to give different instances for e.g. IxMonad m Int a and IxMonad m Integer a, etc. You give up on the "uniformity" of the effect handling.gallais
@gallais I agree, I was fetching terms from memory and got it wrong. Restricted monad is probably a better term. I'm unsure if the real indexed monads can be used for this, I'd guess they can't. CMonad should be a bit more uniform, though.chi