
I've tried something similar before but ran into a lot of cases where verbose intermediate type annotations where necessary to resolve double-wrapping ambiguities because the monad is abstract in my case:
xor :: DSL m r => r S -> r S -> m (r S)
Do I understand correctly that the actual content of the streams is not important, so S is isomorphic to ()? Or are the contents abstracted away into a more complex type? If it's the former, I fail to see why the monadic interface is even necessary. More broadly, could you provide a bigger example of what you're going for? I have a rough idea of what the goal is, but a more specific example might help. I also feel like there might be a way to adapt Sebastiaan's idea still. But if there isn't yet, there is also a pry-bar lying around: RebindableSyntax. All of pure, return, (<*>), fmap, and (>>=) can be overwritten, and will be used in (applicative) do notation. Cheers, MarLinn