为什么MonadReader r(StateT s m)使用底层monad的实例

时间:2016-12-12 07:53:35

标签: haskell monad-transformers

据我所见,我们可以实现MonadReader s (StateT s m)实例:

instance MonadReader s (StateT s m) where
    ask = get
    local f m = do
        s <- get
        put (f s)
        m
        put s   

即。为什么不是

class MonadReader s m => MonadState s m | s -> m where ...

同样,我们可以拥有Monoid s => MonadWriter s (StateT s m)个实例。

选择之间是否有一些深层原因?

这个问题的动机是MonadErrorMonadWriter应该是什么 超级MonadChronicle

2 个答案:

答案 0 :(得分:7)

是的,您可以这样做,但这会违反mtl的精神,并可能导致API问题。 StateT的想法是每个标准monad变换器添加一个或多个不同的效果。将ReaderTStateT添加到变换器堆栈可以为您提供状态和环境。如果MonadReader实现了自己的MonadChronicle实例,那么您可以通过两个不同的接口访问状态blob。要为混合添加环境,您必须使用变换器&#34;手动&#34;。如果您将{{1}}视为提供效果,您可能希望在编写器和异常效果之上进行分层,那么您应该将它们分开。如果您将其视为这些效果的扩展/细化,那么超类就有意义。

答案 1 :(得分:0)

我认为,除了关于MonadReader StateT实例的理论/哲学原因之外,我认为当前的设置也是实用

MonadReaderMonadState提供不同功能的有用。然后,您可以利用askget执行两项不同的操作。如果askget做了同样的事情,那么它几乎就是冗余功能。让它们分开的东西更加实用,并且通过StateTMonadReader实例/接口为MonadState的使用提供了更大的灵活性。

mappend<|> Maybe执行不同事情的原因类似。它只是浪费了潜在的效用:)

我想象如果StateTaskget提供相同的行为,那么人们就会抱怨它是多么不切实际/限制。< / p>