无法为新类型创建MonadTrans的派生实例

Kak*_*aji 2 monads haskell monad-transformers

我有以下新类型声明。它包装了Monad堆栈变压器,堆叠了一些标准的mtl monad,例如Reader和Except。

newtype TrxDbFileBased f a = TrxDbFileBased {
        unTrxDbFileBased :: ExceptT TrxDbError (ReaderT TrxDbFileBasedEnv f) a
    } deriving (
        Functor
    ,   Applicative
    ,   Monad
    ,   MonadError TrxDbError
    ,   MonadReader TrxDbFileBasedEnv
    ,   MonadIO
    ,   MonadTrans
    )

data TrxDbFileBasedEnv = TrxDbFileBasedEnv {
        workingDirectory :: FilePath    
    } deriving (Show)

data TrxDbError = TrxDbErrorIO TrxDbFileBasedEnv IOException
                | TrxDbErrorStr TrxDbFileBasedEnv String 
                deriving (Show)
Run Code Online (Sandbox Code Playgroud)

我希望此新类型是的实例,MonadTrans但出现以下错误。

    • Can't make a derived instance of ‘MonadTrans TrxDbFileBased’
        (even with cunning GeneralizedNewtypeDeriving):
        cannot eta-reduce the representation type enough
    • In the newtype declaration for ‘TrxDbFileBased’
   |        
31 |     ,   MonadTrans
   |         ^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

MonadTrans考虑到基础类型ExceptT是的实例,我不明白为什么不能导出MonadTrans

Fyo*_*kin 6

问题在于,如果此推导有效,则您的实例MonadTrans将转换函子f,而ExceptT您希望用作的基数的实例正在转换monad ReaderT TrxDbFileBasedEnv f

这些在表示上并不等效,因此GeneralizedNewtypeDeriving无法为您提供帮助。

这是另一种思考方法:尝试手动实现该类。如果尝试这样做,您将看到lift必须像这样定义:

lift = TrxDbFileBased . lift . lift
Run Code Online (Sandbox Code Playgroud)

即,第一升降fReaderT,再吊装ReaderTExceptT,然后包装全部在TrxDbFileBased。但是GND希望不进行无操作包装,这意味着直接重复使用方法字典,因为类型在表示上是等效的。您的情况并非如此。