Question

I have the type

ActionT TL.Text (ReaderT T.Text IO)

I'm trying to make a MonadReader instance for this so that I do not have to lift ask, but always get

 (All instance types must be of the form (T a1 ... an)
  where a1 ... an are *distinct type variables*,
  and each type variable appears at most once in the instance head.
  Use -XFlexibleInstances if you want to disable this)

I've tried a bunch of instance types, a couple below, but they always get the above error

instance MonadReader T.Text (ActionT TL.Text (ReaderT T.Text IO))    

instance MonadReader r (ActionT TL.Text (ReaderT r IO))

instance (ScottyError e, MonadReader r m) => MonadReader r (ActionT e (ReaderT r m))

I feel like I'm missing something fundamental with instances. I think I understand FlexibleInstances but I can't see how that applies here.

Any help with the instance type would be appreciated, I would like to implement ask and local myself as the main goal is learning.

Thanks.

Update

I got it working with FlexibleInstances, MultiParamTypeClasses, UndecidableInstances and

instance  (ScottyError e, Monad m, MonadReader r m) => MonadReader r (ActionT e m) where
  ask = lift ask

Still working on the implementation of local. I also assume UndecidableInstances is bad?

Update 2

I think what I really need is.

instance  (ScottyError e, Monad m, MonadReader r m) => MonadReader r (ActionT e (ReaderT r m)) where

But I still cant figure out local

Was it helpful?

Solution 2

The instance would be

instance  (ScottyError e, Monad m, MonadReader r m) => MonadReader r (ActionT e (ReaderT r m)) where

However Scotty does not expose the required functions to implement local.

I am attempting to write a mapActionT to make it possible to implement local and I will update this answer if I ever figure out the types to do that :)

Edit:

I think I have mapActionT, but I'm not sure.

mapActionT :: (Monad m, Functor n, ScottyError e) => (forall a . m a -> n a) -> ActionT e m b -> ActionT e n b
mapActionT nat m = ActionT $ flip mapErrorT (runAM m) $ \rt -> 
        flip mapReaderT rt $ \st ->
            StateT $ \s -> fmap (\a -> (a,s)) (nat (evalStateT st s))

I ended up copying the type signature from hoist so that I could bring in Functor n for my fmap.

Any comments on the implementation are welcome.

OTHER TIPS

As you answered yourself, you need UndecidableInstances to implement the fully generic MonadReader instance. This is a necessary evil, you can see it in all libraries that implement such generic monad type class instances.

I'm afraid that implementing local is going to be a problem. If you look at the standard instances, they all use some kind of mapping function that is specific for a particular monad. And since it seems that neither ActiveT exports such a method or its internals, it doesn't look feasible.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top