monad-control icon indicating copy to clipboard operation
monad-control copied to clipboard

Change definition of StT and StM

Open duog opened this issue 7 years ago • 3 comments

Hi,

Have you considered defining StT and StM as types of kind (* -> *) and requiring a Functor constraint? i.e.

class (MonadTrans t, Functor (StT t)) => MonadTransControl t where
  type StT t :: * -> *
  ...

class (MonadBase b m, Functor (StM m)) => MondBaseControl b m | m -> b where
  type StM m :: * -> *
  ...

This would not preclude any existing instances in monad-control, and I don't know of any instances anywhere that could not be made to satisfy these constraints. The advantages include:

  • The ability to fmap over StT t and StM m
  • The ability to get something akin to MonadTransUnlift with the constraint (StM m ~ Identity) rather than the nasty constraints package tricks that are currently necessary.
  • The potential to discover other useful subsets of MonadBaseControl b m, such as (Applicative (StM m)). Functor has a lot of subclasses.

Obviously this would break every existing instance, but I think we could come up with some CPP snippets that would cover most cases in a backwards compatible way.

I don't really expect that you would be interested in such a breaking change, but if you were I would be happy to discuss further and to offer my assistance in implementation.

duog avatar Jun 07 '17 18:06 duog

interesting idea...

phadej avatar May 11 '21 11:05 phadej

The ability to get something akin to MonadTransUnlift with the constraint (StM m ~ Identity)

Doesn't work as nicely as we'd wish as Compose Identity Identity is not Identity. They are Coercible though, but that's GHC-7.8+, and I don't think that should be a problem for anyone anymore.

phadej avatar Jun 23 '21 12:06 phadej

You may be interested in the Tunnel type of monadology, it's basically this idea. These are the instances:

type Tunnel (ReaderT s) = Identity
type Tunnel (WriterT w) = (,) w
type Tunnel (StateT s) = (,) (Endo s)
type Tunnel MaybeT = Maybe
type Tunnel (ExceptT e) = Either e
type Tunnel (ComposeInner inner) = inner
type Tunnel (ComposeOuter outer) = Identity

It's not just Functor (Tunnel t), there's actually the much stronger constraint MonadInner (Tunnel t). MonadInner is the class of monads that can compose (as the inner monad) with any other monad to make a monad. I use this to enable commuting of transformers within the stack (commuteT).

Overall it's a cleaner and more powerful approach than the current MonadTransControl.

AshleyYakeley avatar Feb 17 '23 20:02 AshleyYakeley