Haskell可以在MonadState s
下面的T1
中派生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)
的实例?
{{1}}
答案 0 :(得分:7)
你不能让一个类型有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
。这需要扩展名FunctionalDependencies
,并声明对于任何m
,我们会自动知道相关的s
。这意味着对于任何给定的m
,s
只能有一个选项才有效。因此除非MonadState r m
,否则您无法让MonadState s m
和r ~ s
同时使用它。如果是r ~ s
,那么编译器将如何知道它应用于哪个底层monad?在这种情况下,我认为如果您创建get
和put
函数,使用后缀来指示哪些函数,getInner
和setInner
函数会更容易理解和使用代码,例如{{ 1}},getOuter
和setOuter
,{{1}}。