Well, my answer is really the same as Toxaris' suggestion of a foo :: Either e a -> Either e' a
function, but I'll try to motivate it a bit more.
A function like foo
is what we call a monad morphism: a natural transformation from one monad into another one. You can informally think of this as a function that sends any action in the source monad (irrespective of result type) to a "sensible" counterpart in the target monad. (The "sensible" bit is where it gets mathy, so I'll skip those details...)
Monad morphisms are a more fundamental concept here than your suggested >>*=
function for handling this sort of situation in Haskell. Your >>*=
is well-behaved if it's equivalent to the following:
(>>*=) :: Monad m => n a -> (a -> m b) -> m b
na >>*= k = morph na >>= k
where
-- Must be a monad morphism:
morph :: n a -> m a
morph = ...
So it's best to factor your >>*=
out into >>=
and case-specific monad morphisms. If you read the link from above, and the tutorial for the mmorph
library, you'll see examples of generic utility functions that use user-supplied monad morphisms to "edit" monad transformer stacks—for example, use a monad morphism morph :: Error e a -> Error e' a
to convert StateT s (ErrorT e IO) a
into StateT s (ErrorT e' IO) a
.