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

Why MonadReader r (StateT s m) uses an instance of the underlying monad

据我所知,我们可以实现 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

的超级 类

是的,您可以这样做,但这会违反 mtl 的精神并可能导致 API 问题。 mtl 的想法是每个标准的 monad 转换器添加一个或多个不同的效果。将 StateTReaderT 添加到转换器堆栈中可以为您提供一个状态和一个环境。如果 StateT 实现了它自己的 MonadReader 实例,那么您将只能通过两个不同的接口访问状态 blob。要将环境添加到混音中,您必须使用变形金刚 "manually"。如果您将 MonadChronicle 视为提供效果,您可能希望在编写器效果和异常效果之上分层,那么您应该将它们分开。如果您将其视为这些效果的 extension/refinement,那么超类就有意义了。

我认为,除了 StateTMonadReader 实例的好的 theoretical/philosophical 原因外,我认为当前的设置也是最 实用.

有用 MonadReaderMonadState 提供不同的功能。然后你可以利用 askget 来做两件不同的事情。如果 askget 做同样的事情,它几乎是多余的功能。让他们分开做事情要实用得多,并且通过 MonadReaderMonadState instances/interfaces.

让你更灵活地使用 StateT

这与 mappend<|> 对于 Maybe 做不同事情的原因类似。这只会浪费潜在的效用:)

我想如果 StateTaskget 给出相同的行为,人们会抱怨 impractical/limiting 会怎样。