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?
Data.Set
should be a functor, but it is not because of theOrd
constraint, for instance. Some more advanced classes have been proposed, like indexed monads, to address this issue, but they never became really popular. – chiclass IxMonad m a b where (>>=) :: m a -> (a->m b) -> m b
allows forinstance IxMonad [] a b
andinstance (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) – chiIxMonad m Int a
andIxMonad m Integer a
, etc. You give up on the "uniformity" of the effect handling. – gallaisCMonad
should be a bit more uniform, though. – chi