[Haskell-cafe] Coercing newtype-wrapped monad transformers?

Viktor Dukhovni ietf-dane at dukhovni.org
Sun May 10 04:27:23 UTC 2020


The code sample below my signature wraps RWS.CPS in a newtype, with a
view to presenting a more constrained interface with specific functions
that internall use the underlying RWST features.

It is straightforward to construct the appropriate variants of "ask",
"get", "put", "tell", ... via appropriate applications of the FooT
constructor and accessor, but I expected to be able to use "coerce",
along the lines of:

        ask :: Monad m => RWST r w s m r
        ask = coerce M.ask

but that fails with:

    foo.hs:34:7: error:
        • Couldn't match representation of type ‘m0’ with that of ‘m’
            arising from a use of ‘coerce’
          ‘m’ is a rigid type variable bound by
            the type signature for:
              ask :: forall (m :: * -> *) r w s. Monad m => FooT r w s m r
            at foo.hs:21:1-34
        • In the expression: coerce M.ask
          In an equation for ‘ask’: ask = coerce M.ask
        • Relevant bindings include
            ask :: FooT r w s m r (bound at foo.hs:34:1)

Somehow between the various constraints and quantifiers in play, coerce
is unable to do what I expected.

Should it have worked?

If had worked, would the effect have been in fact any different (more
efficient?) than what I get with the explicit applications of the
constructor and accessor?

-- 
    Viktor.

{-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleInstances, MultiParamTypeClasses, StandaloneDeriving #-}
import Control.Monad.Trans.Class 
import qualified Control.Monad.Trans.RWS.CPS as M

newtype FooT r w s m a = FooT { unFooT :: M.RWST r w s m a }
deriving instance (Functor m) => Functor (FooT r w s m)
deriving instance (Monad m) => Applicative (FooT r w s m)
deriving instance (Monad m) => Monad (FooT r w s m)
deriving instance MonadTrans (FooT r w s)

runFooT :: (Monoid w, Monad m) => FooT r w s m a -> r -> s -> m (a, s, w)
execFooT :: (Monoid w, Monad m) => FooT r w s m a -> r -> s -> m (s, w)
evalFooT :: (Monoid w, Monad m) => FooT r w s m a -> r -> s -> m (a, w)
ask :: (Monad m) => FooT r w s m r
asks :: (Monad m) => (r -> a) -> FooT r w s m a
get :: (Monad m) => FooT r w s m s
gets :: (Monad m) => (s -> a) -> FooT r w s m a
modify :: (Monad m) => (s -> s) -> FooT r w s m ()
pass :: (Monoid w, Monoid w', Monad m) => FooT r w' s m (a, w' -> w) -> FooT r w s m a
put :: (Monad m) => s -> FooT r w s m ()
tell :: (Monoid w, Monad m) => w -> FooT r w s m ()

runFooT = M.runRWST . unFooT
evalFooT = M.evalRWST . unFooT
execFooT = M.execRWST . unFooT
ask = FooT $ M.ask
asks = FooT . M.asks
get = FooT $ M.get
gets = FooT . M.gets
modify = FooT . M.modify
pass = FooT . M.pass . unFooT
put = FooT . M.put
tell = FooT . M.tell

main :: IO ()
main = runFooT mfoo "read me" "set me" >>= print
  where
    mfoo = do
        ask >>= modify . (. (" or " ++)) . (++)
        tell "Hello"
        pass $ do
            tell "World!"
            pure (42, (' ':))


More information about the Haskell-Cafe mailing list