concrete functor and monad transformers

#66Alternative and MonadPlus instances for ContT

The laws seem to check out and Codensity from kan-extensions has them as well.

Codensity is the same as ContT but with a universally qualified return type, so you can not do things like callCC:

newtype Codensity m a = Codensity { runCodensity :: forall b . (a -> m b) -> m b }

This is what these instances would look like:

instance (Monad m, Alternative m) => Alternative (ContT r m) where
  empty = lift empty
  ContT mx <|> ContT my = ContT $ \cont -> mx cont <|> my cont
instance (Monad m, Alternative m) => MonadPlus (ContT r m)
    • description updated
  • Ok, actually I this does not honour the right identity of mzero, i.e: m >> mzero = mzero. E.g:

    >>> (`runContT` pure) $ ContT $ \_ -> pure () :: Maybe ()
    Just ()

    Alternative does not have that law though, so that would still be possible. But if you do not want a type that is both a Monad and an Alternative but not a MonadPlus I would understand that.

    Another question would be whether empty should be lift empty or ContT $ \_ -> empty. The former at least satisfies the left identity of mzero, but the latter does not require a Monad constraint on m.

    • description updated
  • That should have been

    >>> (`runContT` pure) $ (ContT $ \_ -> pure ()) >> mzero :: Maybe ()
    Just ()
    • status set to closed

    Closing this issue, as I think these instances are not well behaved enough. Even for Alternative I would expect fa *> mzero = mzero, even if it is not stated in the laws.