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

时间:2017-08-23 04:16:13

标签: haskell action monads haskell-snap-framework

我一直在学习haskell已经有一段时间了,我刚刚读完'了解你是一个非常好的Haskell'。我的问题来自我目前正在努力完成的任务。基本上,我一直在使用Snap框架,我现在很难理解状态(在这种情况下是Request + Response对象,MonadSnap)在进行如下调用时是如何变异的:

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

我无法弄清modifyResponse方法如何改变底层MonadSnap,只是将其指定为类型约束。

我在搜索答案时遇到过这个类似的概念,如果我想保持状态并使下面的函数按预期工作,我会相信相同的答案,例如this answer中提出的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

2 个答案:

答案 0 :(得分:2)

以下是modifyResponse的{​​{3}}:

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

MonadSnap类型类中唯一的函数是source code,而类型类的唯一预定义实例是liftSnap monad(它被定义为liftSnap = id

这只是一小部分间接,以便允许该函数与其他实现MonadSnap的类型一起使用。它使得处理Snap堆栈变得更加容易。签名可能是:

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

现在,也许您的下一个问题是:smodify如何运作?”

这是Monad Transformer

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

正如你所看到的,它不是魔术,只是功能。内部SnapState对您隐藏,因为您不需要知道Snap的内部以便使用它。就像你不需要知道IO monad的内部以便使用它一样。

答案 1 :(得分:1)

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,就可以轻松地通过Snap a将具体的m a转换为liftSnap

通过成功使用新的Snap和单位()来修改具体的is done状态SnapStatesk是成功做法的成功延续。

-- | 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。传递给f的函数smodify是仅修改_snapResponse记录的SnapState字段的函数。

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