Need help using a typeclass within an existing API

Hi - (Apologies for the long post) I need some help integrating a typeclass based functionality within an existing API. I am using Control.Monad.Validate for my validation of objects. Here's a simple function based on this .. debit :: forall m. (MonadReader Env m, MonadValidate [Error] m) => Y.Dense "USD" -> Account -> m Account debit amount = updateBalance ((-1) * amount) Now I want to make a change in the API where I would like to fetch the account from some database based on account number. For this I have a typeclass as below .. class (Monad m) => AccountDB m where query :: Text -> m (Maybe Account) .. elided details and I am using persistent - so I have an instance of this class as follows .. -- | Instance of AccountDB for `SqlPersistT` (which is `ReaderT SqlBackend`) instance (MonadIO m) => AccountDB (SqlPersistT m) where query ano = get (AccountKey ano) .. other details elided My question is how can I integrate this typeclass within the above API ? I tried as yet another constraint in the function .. debit :: forall m. (MonadReader Env m, MonadValidate [Error] m, AccountDB m) => Y.Dense "USD" -> Text -> m Account debit amount accNo = do maybeAccount <- query accNo maybe (refuteErr $ InvalidAccountNumber accNo) (updateBalance ((-1) * amount)) maybeAccount This compiles but I don't get the proper instance of the typeclass when I run it - possibly due to the reason that the "m" cannot be the same for AccountDB as the other constraints. And I don't want to hardcode SqlPersistT in the function debit as I would like to be able to run it with other instances of the typeclass as well (example for testing I may like to test against a HashMap). What would be an idiomatic approach to this kind of composition ? Any help will be appreciated. regards. -- Debasish Ghosh http://manning.com/ghosh2 http://manning.com/ghosh Twttr: @debasishg Blog: http://debasishg.blogspot.com Code: http://github.com/debasishg

This compiles but I don't get the proper instance of the typeclass when I run it
You did not tell us to which concrete type M you instantiate the type variable m when you run your code. Your wording suggests that you may misunderstand how instantiation of type variables works: it is the caller of the debit function who chooses the M; in fact it can choose /any/ M, as long as it satisfies the listed constraints. If your code compiles but doesn't work, then the M your caller has chosen has a wrong instance that doesn't do what it should do. If it is not obvious from the calling code what the M is, try to use local type annotations with type holes, so the compiler tells you what the type is. Cheers Ben
participants (2)
-
Ben Franksen
-
Debasish Ghosh