【问题标题】:Why MonadReader r (StateT s m) uses an instance of the underlying monad为什么 MonadReader r (StateT s m) 使用底层 monad 的实例
【发布时间】:2016-12-12 07:53:34
【问题描述】:

据我所知,我们可以实现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 =&gt; MonadWriter s (StateT s m) 实例。

选择之间有什么深层次的原因吗?


这个问题的动机是 MonadErrorMonadWriter 是否应该 MonadChronicle的超类

【问题讨论】:

  • 这只是mtl的限制。您可以查看其他库。 This post可以帮助你更多。
  • @freestyle,那个帖子是关于稍微不同的问题。我试图澄清这个问题:为什么 MonadReader 不是 MonadState 的超类
  • 我想你会想问另一个问题:当我的堆栈上有 State monad 时,为什么我不能使用 MonadReader 或 MonadWriter 接口?所以我只是试着回答一下。

标签: haskell monad-transformers


【解决方案1】:

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

【讨论】:

  • 所以,我可以写RWST s m(n.b:仅s),实现MonadReader sMonadWriter sMonadState s。我想知道是否有人在他们的公共或私人开发中做到了这一点。我怀疑使用镜头,只有一个变压器就足够了。我很想了解潜在的 API 问题。
  • @phadej 我会称它为State2 或其他名称,但不是RWS,因为RWS 的意义在于保证只读部分和保证仅追加部分,超出状态的读/写部分。如果只有s,我猜我们实际上有一个State newtype,除了更多实例(这不是一个坏主意,因为你提到的原因)。
【解决方案2】:

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

MonadReaderMonadState 提供不同的功能会更有用。然后你可以利用askget 来做两件不同的事情。如果askget 做同样的事情,那几乎就是多余的功能。让他们做单独的事情更加实用,并且通过 MonadReaderMonadState 实例/接口让您在使用 StateT 时更加灵活。

这与为什么 mappend&lt;|&gt; for Maybe 做不同事情的原因相似。这只会浪费潜在的效用:)

我想如果StateTaskget 给出相同的行为,人们会抱怨它是多么不切实际/限制。

【讨论】:

  • 最不幸的是,mappend&lt;|&gt;Maybe 做不同的事情。
  • @dfeuer 为什么你认为这很不幸?有一个 Alt 包装器,以及 First
猜你喜欢
  • 1970-01-01
  • 2013-09-11
  • 1970-01-01
  • 2014-05-10
  • 1970-01-01
  • 2020-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多