返回空动作时如何改变状态

How can one mutate a state when returning an empty action

学习haskell有一段时间了,刚刚读完'Learn you a Haskell for great good'。我的问题来自我目前正在尝试完成的作业。基本上,我一直在使用 Snap Framework,目前我很难理解状态(在本例中是 Request + Response 对象,即 MonadSnap)在进行如下调用时是如何发生变化的:

modifyResponse :: MonadSnap m => (Response -> Response) -> m ()

我不太明白 modifyResponse 方法如何在仅将其指定为类型约束的情况下改变底层 MonadSnap

我在搜索答案时遇到了这个类似的概念,我相信如果我想保持状态并使以下功能按预期工作,同样的答案也会适用,就像 [=14 中提出的 OP =]:

instance M Monad where ...

-- Modify the counter and do not produce any result:
incrementCounter :: M ()
decrementCounter :: M ()

-- Get the current value of the counter
readCounter :: M Integer

这是 modifyResponsesource code

modifyResponse :: MonadSnap m => (Response -> Response) -> m ()
modifyResponse f = liftSnap $
     smodify $ \ss -> ss { _snapResponse = f $ _snapResponse ss }

MonadSnap 类型类中唯一的函数是 liftSnap, and the only pre-defined instance of the typeclass is the Snap monad(定义为 liftSnap = id)。

这只是一点点间接,目的是让该函数可以与其他实现了 MonadSnap 的类型一起工作。它使使用 Monad Transformer 堆栈变得更加容易。签名可能是:

modifyResponse :: (Response -> Response) -> Snap ()

现在,也许你的下一个问题是:"How does smodify work?"

这是 source code:

smodify :: (SnapState -> SnapState) -> Snap ()
smodify f = Snap $ \sk _ st -> sk () (f st)

如您所见,这不是魔法,只是函数。内部 SnapState 对你是隐藏的,因为你不需要知道 Snap 的内部就可以使用它。就像你不需要了解 IO monad 的内部结构就可以使用它一样。

MonadSnap 的每个实例都必须提供一个 liftSnap 方法:

-- | 'MonadSnap' is a type class, analogous to 'MonadIO' for 'IO', that makes it
-- easy to wrap 'Snap' inside monad transformers.
class (Monad m, MonadIO m, MonadBaseControl IO m, MonadPlus m, Functor m,
       Applicative m, Alternative m) => MonadSnap m where
  -- | Lift a computation from the 'Snap' monad.
  liftSnap :: Snap a -> m a

这意味着只要有 MonadSnap m 就可以很容易地通过 liftSnap.

将具体的 Snap a 转换为 m a

修改具体Snap's state is done by succeeding with the new SnapState和单位()值。 sk 是成功后要做什么的成功延续。

-- | Local Snap monad version of 'modify'.
smodify :: (SnapState -> SnapState) -> Snap ()
smodify f = Snap $ \sk _ st -> sk () (f st)
{-# INLINE smodify #-}

modifyResponsesmodifySnap a 提升到 MonadSnap m => m a。传递给 smodify 的函数 f 是一个仅修改 SnapState 记录的 _snapResponse 字段的函数。

modifyResponse :: MonadSnap m => (Response -> Response) -> m ()
modifyResponse f = liftSnap $
     smodify $ \ss -> ss { _snapResponse = f $ _snapResponse ss }
{-# INLINE modifyResponse #-}