[Haskell-cafe] Best way to provide monad transformer instances in library design?

Matt parsonsmatt at gmail.com
Fri Feb 3 16:32:45 UTC 2017


I'm writing a wrapper around ekg which provides an MTL-style class for
recording metrics [1], and now I'm trying to figure out how to make the
class usable for clients.

I'm conflicted on the numerous ways to approach the problem. I would like
to provide the best UX for the library, and want to consider viewpoints
other than my own.

Currently, the class is:

class MonadMetrics m where getMetrics :: m Metrics

I currently don't provide any concrete transformer, instead requiring that
users define it for their own stacks. I'd like to make it easier to use.

I can provide a concrete transformer

newtype MetricT m a = MetricT (ReaderT Metrics m a)
instance Monad m => MonadMetrics (MetricT m) where getMetrics = MetricT ask

and then provide a wide variety of pass through instances. This approach
requires a large amount of boilerplate, and for any instances I forget to
provide, will require that clients make their own orphan instances. It also
incurs additional dependencies just for writing instances.

I can provide a more abstract transformer and a more general Metrics class:

class HasMetrics r where metrics :: Lens' r Metrics

newtype MetricT2 m a = MetricT2 (m a)
instance (MonadReader r m, HasMetrics r) => MonadMetrics (MetricT2 m) where
    getMetrics = MetricT (view metrics)

but this still requires those pass through instances.

Finally, I can scrap `MonadMetrics` as anything other than a class alias:

class (MonadReader r m, MonadIO m, HasMetrics r) => MonadMetrics r m
instance (MonadReader r m, MonadIO m, HasMetrics r) => MonadMetrics r m

but now I have UndecidableInstances and a multiparam type class, and I'm
not sure how well this actually plays out in the wild.

What are your thoughts on this issue?

Matt Parsons

[1]: https://github.com/sellerlabs/monad-metrics
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20170203/8b2ca71d/attachment.html>


More information about the Haskell-Cafe mailing list