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 mr ~ s。如果是r ~ s,那么编译器将如何知道要对其应用哪个底层monad?在这种情况下,我认为您还会发现,如果创建带有后缀以指示哪一个的getput函数,例如getInnersetInnergetOutersetOuter,那么理解和使用该代码将更加容易。

10-07 12:08