Haskell 广义新类型导出

Haskell 广义新类型导出,haskell,monads,state-monad,deriving,newtype,Haskell,Monads,State Monad,Deriving,Newtype,Haskell可以在下面的T1中派生出MonadState s的实例,但在T2中却不能派生出该实例,但这是一种非常类似的类型。我应该以何种方式修改T2的代码,以便可以自动派生MonadState s的实例 {-# LANGUAGE GeneralizedNewtypeDeriving #-} import Control.Monad.Reader import Control.Monad.State newtype T1 r s a = T1 { runT1 :: ReaderT r

Haskell可以在下面的
T1
中派生出
MonadState s
的实例,但在
T2
中却不能派生出该实例,但这是一种非常类似的类型。我应该以何种方式修改
T2
的代码,以便可以自动派生
MonadState s
的实例

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

import Control.Monad.Reader
import Control.Monad.State

newtype T1 r s a = 
  T1 { runT1 :: ReaderT r (State s) a }
  deriving (Monad, MonadReader r, MonadState s)

newtype T2 r s a = 
  T2 { runT2 :: StateT r (State s) a }
  deriving (Monad, MonadState r, MonadState s)

对于
MonadState
,不能有一个具有两个实例的类型。这是因为
MonadState
被定义为

class Monad m => MonadState s m | m -> s where
    get :: m s
    set :: s -> m ()
    state :: (s -> (a, s)) -> m a
关键部分是
|m->s
。这需要扩展名
功能相关性
,并说明对于任何
m
,我们都会自动知道相关的
s
。这意味着对于任何给定的
m
,对于
s
只能有一个有效的选项。因此,除非
r~s
,否则不能让它同时适用于
MonadState rm
MonadState sm
。如果
r~s
,那么编译器如何知道应用它的底层monad?在这种情况下,我想您还会发现,如果您创建
get
put
函数,这些函数都有后缀来指示哪些函数,比如
getInner
setInner
getOuter
setOuter
,那么理解和使用代码就会容易得多