据我所见,我们可以实现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)
个实例。
选择之间是否有一些深层原因?
这个问题的动机是MonadError
和MonadWriter
应该是什么
超级MonadChronicle
答案 0 :(得分:7)
是的,您可以这样做,但这会违反mtl
的精神,并可能导致API问题。 StateT
的想法是每个标准monad变换器添加一个或多个不同的效果。将ReaderT
和StateT
添加到变换器堆栈可以为您提供状态和环境。如果MonadReader
实现了自己的MonadChronicle
实例,那么您可以通过两个不同的接口访问状态blob。要为混合添加环境,您必须使用变换器&#34;手动&#34;。如果您将{{1}}视为提供效果,您可能希望在编写器和异常效果之上进行分层,那么您应该将它们分开。如果您将其视为这些效果的扩展/细化,那么超类就有意义。
答案 1 :(得分:0)
我认为,除了关于MonadReader
StateT
实例的理论/哲学原因之外,我认为当前的设置也是实用。
让MonadReader
和MonadState
提供不同功能的有用。然后,您可以利用ask
和get
执行两项不同的操作。如果ask
和get
做了同样的事情,那么它几乎就是冗余功能。让它们分开的东西更加实用,并且通过StateT
和MonadReader
实例/接口为MonadState
的使用提供了更大的灵活性。
mappend
和<|>
Maybe
执行不同事情的原因类似。它只是浪费了潜在的效用:)
我想象如果StateT
为ask
和get
提供相同的行为,那么人们就会抱怨它是多么不切实际/限制。< / p>