Proposal: DerivingVia, MTL

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Proposal: DerivingVia, MTL

Reed Mullanix
As it stands, working with newtypes around transformers can be kind of a pain. For example,
consider

newtype FreshT m a = { unFreshT :: StateT Int m a }
  deriving (Functor, Applicative, Monad, MonadReader r, ...)

Right now, we can't just GND the instance:

instance (MonadState s m) => MonadState s (FreshT m)

However, the instance we end up writing is completely formulaic. Fortunately, we can solve this by using the recently added -XDerivingVia

newtype Inner (t :: (* -> *) -> * -> *) m a = Inner { getInner :: t m a }
  deriving (Functor, Applicative, Monad)

instance (MonadState s m) => MonadState s (Inner (StateT s') m) where
  get = Inner $ lift get
  put = Inner . lift . put

This lets us derive the instance that we were looking for

newtype FreshT m a = FreshT { unFreshT :: StateT Int m a }
  deriving newtype (Functor, Applicative, Monad, MonadReader r)
  deriving (MonadState s) via Inner (StateT Int) m

This can be extended to other transformers/classes very easily. It also works well when dealing with newtyped transformer stacks.

newtype FooT s e m a = FooT { unFooT :: StateT s (WriterT String (ExceptT e m)) a }
  deriving newtype (Functor, Applicative, Monad, MonadError e)
  deriving (MonadWriter w) via (StateT s (Inner (WriterT String) (ExceptT e m)))
  deriving (MonadState s') via Inner (StateT s) (WriterT String (ExceptT e m))

Cheers,
Reed Mullanix

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: DerivingVia, MTL

chessai .
I'm confused. This seems more like a helpful tip than a proposal. Where is the proposal?

On Sun, May 19, 2019, 9:27 PM Reed Mullanix <[hidden email]> wrote:
As it stands, working with newtypes around transformers can be kind of a pain. For example,
consider

newtype FreshT m a = { unFreshT :: StateT Int m a }
  deriving (Functor, Applicative, Monad, MonadReader r, ...)

Right now, we can't just GND the instance:

instance (MonadState s m) => MonadState s (FreshT m)

However, the instance we end up writing is completely formulaic. Fortunately, we can solve this by using the recently added -XDerivingVia

newtype Inner (t :: (* -> *) -> * -> *) m a = Inner { getInner :: t m a }
  deriving (Functor, Applicative, Monad)

instance (MonadState s m) => MonadState s (Inner (StateT s') m) where
  get = Inner $ lift get
  put = Inner . lift . put

This lets us derive the instance that we were looking for

newtype FreshT m a = FreshT { unFreshT :: StateT Int m a }
  deriving newtype (Functor, Applicative, Monad, MonadReader r)
  deriving (MonadState s) via Inner (StateT Int) m

This can be extended to other transformers/classes very easily. It also works well when dealing with newtyped transformer stacks.

newtype FooT s e m a = FooT { unFooT :: StateT s (WriterT String (ExceptT e m)) a }
  deriving newtype (Functor, Applicative, Monad, MonadError e)
  deriving (MonadWriter w) via (StateT s (Inner (WriterT String) (ExceptT e m)))
  deriving (MonadState s') via Inner (StateT s) (WriterT String (ExceptT e m))

Cheers,
Reed Mullanix
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: DerivingVia, MTL

Reed Mullanix
Sorry, I should've been more clear. The proposal is to add the Inner newtype and it's associated instances to MTL.

On Sun, May 19, 2019, 7:57 PM chessai ., <[hidden email]> wrote:
I'm confused. This seems more like a helpful tip than a proposal. Where is the proposal?

On Sun, May 19, 2019, 9:27 PM Reed Mullanix <[hidden email]> wrote:
As it stands, working with newtypes around transformers can be kind of a pain. For example,
consider

newtype FreshT m a = { unFreshT :: StateT Int m a }
  deriving (Functor, Applicative, Monad, MonadReader r, ...)

Right now, we can't just GND the instance:

instance (MonadState s m) => MonadState s (FreshT m)

However, the instance we end up writing is completely formulaic. Fortunately, we can solve this by using the recently added -XDerivingVia

newtype Inner (t :: (* -> *) -> * -> *) m a = Inner { getInner :: t m a }
  deriving (Functor, Applicative, Monad)

instance (MonadState s m) => MonadState s (Inner (StateT s') m) where
  get = Inner $ lift get
  put = Inner . lift . put

This lets us derive the instance that we were looking for

newtype FreshT m a = FreshT { unFreshT :: StateT Int m a }
  deriving newtype (Functor, Applicative, Monad, MonadReader r)
  deriving (MonadState s) via Inner (StateT Int) m

This can be extended to other transformers/classes very easily. It also works well when dealing with newtyped transformer stacks.

newtype FooT s e m a = FooT { unFooT :: StateT s (WriterT String (ExceptT e m)) a }
  deriving newtype (Functor, Applicative, Monad, MonadError e)
  deriving (MonadWriter w) via (StateT s (Inner (WriterT String) (ExceptT e m)))
  deriving (MonadState s') via Inner (StateT s) (WriterT String (ExceptT e m))

Cheers,
Reed Mullanix
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries