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)
最佳答案
您不能让类型具有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
和getOuter
,setOuter
,那么理解和使用该代码将更加容易。