Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MonadTransControl is impossible to implement for transformer-transformers #19

Open
IreneKnapp opened this issue May 5, 2014 · 2 comments

Comments

@IreneKnapp
Copy link

Imagine that I have a monad-transformer transformer; that is, a datatype which is parameterized on a monad transformer, and which is itself a monad transformer. This came up for me in the context of writing a wrapper layer that applied additional semantics around an existing monad transformer under my control.

Then, it is impossible to ever write a MonadTransControl instance on this datatype. (It's also impossible to write MonadTrans).

The reason is quite simple: The types of the liftWith and restoreT methods each introduce an additional constraint on Monad m, for an arbitrary monad not mentioned in the class signature. To write my wrapper, I need to invoke these methods recursively, calling them on the inner layer, as in:

instance MonadTransControl innerT => MonadTransControl (WrapperTT innerT) where
  liftWith = WrapperTT . liftWith
  restoreT = WrapperTT . restoreT

But these inner methods are looking for an instance Monad (innerT m), for all m. This condition in fact holds, since innerT is itself a monad transformer, but there is no way to ever prove it to Haskell!

It cannot be deduced from the existence of a relevant instance elsewhere, because that is not how instance constraints work; rather, only instances explicitly mentioned in some context are relevant to what the compiler is trying to prove. The relevant contexts are those on the method definitions, the instance definition, and the class definition. Since m is introduced at the method level, it is out-of-scope and cannot be mentioned at the instance level.

So, this true fact can neither be deduced automatically, nor supplied explicitly. How Gödelian.

I'm filing this bug here, and I will also file it against the base package if it turns out to be easy to do so, since, as I noted MonadTrans has the same problem. I don't have a solution in mind, and I don't expect that anyone else does either, but I want the issue to be well-described so that future architects can chew on it. I will not be hurt when this inevitably gets closed as WONTFIX! :)

By the way - to anyone finding this via google - my sympathies! What I ultimately did was implement MonadBase and MonadBaseControl directly, rather than using the default* helpers, which introduce otherwise-unneeded constraints on MonadTrans and MonadTransControl.

@basvandijk
Copy link
Owner

Hi Irene,

Could you provide your WrapperTT datatype and your final working solution? I would be interested in that!

Thanks.

@IreneKnapp
Copy link
Author

Hi,

I don't own that code and no longer have a copy of it, sorry. What I ultimately did was to use monad-control only for the layers below this one in the stack, modifying all call sites to manually lift past it, as if by inlining the hypothetical MonadTransControl instance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants