-
Notifications
You must be signed in to change notification settings - Fork 16
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
Add MFunctor instances #28
base: master
Are you sure you want to change the base?
Conversation
If you think this is valuable, I'll go on documenting. Maybe an example in the module doc? And some comments on the instances? |
@HeinrichApfelmus ping :) any interest? Are docs needed? |
Thanks for pinging me! I finally managed to take a look, specifically concerning the question of whether this function requires access to the constructors or not. 🤔 Wow. 😲 It looks like the definition of If the target were a monad, we could write the following function in terms of hoistProgramT
:: (Monad m, Monad n)
=> (forall a. m a -> n a)
-> ProgramT instr m b
-> ProgramT instr n b
hoistProgramT nat program =
joinProgramT $ nat $ do
firstInstruction <- viewT program
return $ case firstInstruction of
Return a -> return a
i :>>= k -> singleton i >>= (hoistProgramT nat . k)
joinProgramT :: Monad n => n (ProgramT instr n a) -> ProgramT instr n a
joinProgramT = join . lift and then define instance MFunctor (ProgramT instr) where
hoist = hoistProgramT However, the Haskell compiler will reject this definition of The reason why you are able to implement it with direct access to the constructors is that the constructor Lift :: m a -> ProgramT instr m a
-- vs
lift :: Monad m => m a -> ProgramT instr m a Hm. Given that I think that the definition of |
Thanks for coming back to this! :)
I don't quite agree with your assessment. See Gabriella439/Haskell-MMorph-Library#11, people have suggested to add the additional constraint before, and it wasn't needed. I've written quite a few So in summary I believe that:
|
I'm afraid, but I disagree on this point. 😅
hoistProgramT
:: (Monad m, Monad n)
=> (forall a. m a -> n a)
-> ProgramT instr m b
-> ProgramT instr n b exists, and that a function with type signature hoist
:: Monad m
=> (forall a. m a -> n a)
-> ProgramT instr m b
-> ProgramT instr n b most likely does not exist. I'm happy to add an implementation |
The idea behind
MFunctor
is thatProgramT
andProgramViewT
should be compatible with functions likelift :: MonadTrans t => m x -> t m x
,liftIO :: MonadIO m => IO x -> m x
,flip evalStateT s :: StateT s m a -> m a
,flip runReaderT r :: ReaderT r m a -> m a
, and so on. Such functions are "monad morphisms", andhoist
allows to use them on the inner monad of an operational construction.For example,
hoist liftIO :: MonadIO m => ProgramT instr IO a -> ProgramT instr m a
.Another typical use case is when you want to handle some part of your monad stack inside
ProgramT
, i.e.hoist $ flip runReaderT r :: ProgramT (ReaderT r m) a -> ProgramT m a
.I often need functions like this.
To do