7

Haskell 可以推导出MonadState sinT1下面的实例,但不是 in T2which 是非常相似的类型。我应该以哪种方式修改代码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)
4

1 回答 1

9

你不能让一个类型有两个实例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 mMonadState s m除非r ~ s。如果r ~ s,那么编译器如何知道它适用于哪个底层 monad?在这种情况下,我认为您还会发现,如果您创建getput函数具有后缀来指示哪个,例如getInnersetInnergetOuter,会更容易理解和使用代码setOuter

于 2014-09-05T20:40:14.163 回答