I am trying to write a ‘logger’ Monad Transformer. Other Monad Transformers will then be applied to it, to form a more complex monad. I want the logger function to work on all these monads, so I wrote a typeclass as follows.
class Logger e m | m -> e where
logMessage :: e -> m ()
The reason I use Functional Dependencies here, is that the monad m
will explicitly contain the type e
(as what it is with State
monad), which stands for the message type.
The transformer ET
is made an instance of typeclass Logger.
data ET e m a = ET { ... }
instance Monad m => Monad (ET e m) where
logMessage msg = ...
instance Monad m => Logger e (ET e m) where
logMessage msg = ...
Now, I want the monad T1 (T2 ... (ET m))
(which has an ET
in the transformer chain) to be an instance of typeclass Logger
, but it failed to compile. Below is the code.
instance (Logger e m, MonadTrans t) => Logger e (t m) where
logMessage = lift . logMessage
I thought that since t
is only a Monad Transformer, and m
is guaranteed to uniquely determine e
, then t m
should also uniquely determine e
. But the compiler seems to think differently.
Test.hs:43:10: error:
? Illegal instance declaration for ‘Logger e (t m)’
The coverage condition fails in class ‘Logger’
for functional dependency: ‘m -> e’
Reason: lhs type ‘t m’ does not determine rhs type ‘e’
Un-determined variable: e
Using UndecidableInstances might help
? In the instance declaration for ‘MonadException e (t m)’
|
43 | instance (Logger e m, MonadTrans t) => Logger e (t m) where
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.
Can anyone explain how the extension FunctionalDependencies
works, as well as how to solve this problem?
The compiler I use is The Glorious Glasgow Haskell Compilation System, version 8.2.2
, on Windows 10.