
I tried to implement a polymorphic serializer that uses a enclosed MVar () to serialize an action in an arbitrary IO monad, without a need for its user to resort to explicit liftIO calls. So, as a first step I create a typeclass that has a natural default implementation, and some instances for the Monads of interest that just use the natural default: type Serially m = (MonadIO m) => forall a. IO a -> m a class (MonadIO m) => Serializable m where serialize :: MVar () -> Serially m serialize lock = liftIO . withMVar lock . const instance Serializable IO instance Serializable (StateT Int IO) ... With this, given: foo :: Serially IO -> ... -> IO () foo serially ... = do ... serially $ ... ... bar :: Serially (StateT Int IO) -> ... -> StateT Int IO () bar serially ... = do ... serially $ ... ... I can write: lock <- newMVar () foo (serialize lock) ... bar (serialize lock) and the type system figures out the correct version of serialize for foo's and bar's actual monad. Is it possible to create a single "serialize lock" closure that works for both "foo" and "bar"? Something that works along the lines of: let x = liftIO . withMVar lock . const :: ??? foo x ... bar x ... If I leave out the "liftIO", then I can of course use: x :: forall a. IO a -> IO a and the "liftIO" can be put explicitly into "foo" and "bar". foo x ... = liftIO $ x $ ... bar x ... = liftIO $ x $ ... but is it possible for "x" to both be polymorphic with respect to its user's monad and at the same time to be a *closure* around some MVar, and thus not directly a method of a type class. Of course needing to add an extra "liftI0" here and there is not onerous, I'm mostly just curious whether I'm missing something that can hide that boilerplate call in the serializer implementation. -- Viktor.