Open wdanilo opened 10 years ago
A problem that I see with MonadMorph is that there can be multiple valid monad morphisms between two monads. For example:
Just . flip S.evalState (0 :: Int) :: S.State Int a -> Maybe a
(\(x, s) -> if s > 5 then Just x else Nothing) . flip S.runState (0 :: Int)
:: S.State Int a -> Maybe a
There are probably, similar, typeclasses more specific to what they apply to and what they produce that would conform to useful laws however.
@Davorak I know it, but still this functionality is often and widely used. Maybe the name is wrong, maybe it should be named
class DefaultMorph m n where
defaultMorph :: m a -> n a
I'm talking about providing instances for some default monad morphs. This starts to be interesting when using the hoist
function.
With the above implementation, the hoist defaultMorph
has signature of DefaultMorph m n => t m b -> t n b
which is very handy sometimes. What do you think about it?
My main issue with this is that it only works for the special case where you transform just one layer. To illustrate this, consider the case where I want morph
to transform two layers at once, like this:
morph :: ReaderT s Identity r -> StateT s IO r
I might try to write an instance like this:
instance MMorph (ReaderT s Identity) (StateT s IO) r
morph = readOnly . hoist generalize
-- `readOnly` is a monad morphism
readOnly :: Monad m => ReaderT s m r -> StateT s m r
readOnly (ReaderT k) = StateT (\s -> do
r <- k s
return (r ,s) )
That instance obeys the monad morphism laws, but now we have to write N^2 such instances, where N is the number of monad morphisms that change just one layer. Really, we'd like to only define instances that change just one layer, like this:
instance Monad m => MMorph (ReaderT s m) (StateT s m) where
mmorph = readOnly
instance Monad m => MMorph Identity IO where
mmorph = generalize
... and then somehow compose them into instances that change multiple layers at a time.
However, we have no good way to "connect" those two instances into one that would correctly auto-convert ReaderT s Identity
to StateT s IO
. And we can't do mmorph . mmorph
because then the compiler can't infer what the intermediate type would be unless we explicitly annotate the intermediate types, but that is no less verbose than just explicitly picking the monad morphisms we wish to apply.
I think the closest to this is the already existing MonadBase
: https://hackage.haskell.org/package/transformers-base/docs/Control-Monad-Base.html#t:MonadBase
Hello! Is it possible to add a MonadMorph type class to the library? Its implementation is very simple:
It allows to define possible morphisms between monads. Right now I and some of my friends are using such class in connection to mmorph lib and I think it should be just built in, what do you think? :)