danidiaz / dep-t

Dependency injection for records-of-functions.
http://hackage.haskell.org/package/dep-t
BSD 3-Clause "New" or "Revised" License
8 stars 2 forks source link

Add some variadic function to simplify dependency invocation? #1

Closed danidiaz closed 3 years ago

danidiaz commented 3 years ago

Invoking functions stored in a record-of-functions while in a ReaderT / DepT is kind of verbose. I asked about that in SO some time ago.

Perhaps one of the answers to that question could be added to this package.

danidiaz commented 3 years ago

If we want to leave the function polymorphic on the monad, as in bc3aca3ce638443b6fcbaa4ab67a6a5f739dc816 , then we have a big problem: the typeclass that implements the variadic function can't be sure if the m is a function or not, and gets very confused.

* Could not deduce (Call'
                      r0
                      (TheMonad' (m ()) (IsFunction (m ())))
                      (m ())
                      (IsFunction (m ())))
    arising from a use of `call'
  from the context: (MonadReader e m, HasLogger e m,
                     HasRepository e m)
    bound by the type signature for:
               mkController :: forall e (m :: * -> *).
                               (MonadReader e m, HasLogger e m, HasRepository e m) =>
                               Int -> m Int
danidiaz commented 3 years ago

Another thing that I tried here fefa627d11722d71e6b3311b6f738f0eb4a291d1 was to have a MonadDep typeclass. The idea was that, given that concrete monads know if they are different from (a ->) or not, I could delegate the variadic logic on each concrete monad.

MonadDep had a type family that produced different constraints depending on the monad, and the constraints were applied ton the method. I'm surprised that it compiled at all!

Alas, it doesn't work:

test\tests.hs:43:3: error:
    * Could not deduce: WhatConstraintToUse r0 m0 r0 (String -> m ())
        arising from a use of `callx'
      from the context: (MonadDep e m, HasLogger e m, HasRepository e m)
        bound by the type signature for:
                   mkController :: forall e (m :: * -> *).
                                   (MonadDep e m, HasLogger e m, HasRepository e m) =>
                                   Int -> m Int

Similar problem as before: polymorphic monad = trouble.

danidiaz commented 3 years ago

A consolation price is that one can write auxiliary functions for each HasX typeclass, like this:

logger' :: (MonadReader r m, HasLogger r m) => String -> m ()
logger' msg = do
    f <- asks logger
    f msg

And use them like this:

mkController :: (MonadReader e m, HasLogger e m, HasRepository e m) => Int -> m Int
mkController x = do
  logger' "I'm going to insert in the db!"

It's more boilerplate though.