我一直在学习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
答案 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
如何运作?”
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状态SnapState
。 sk
是成功做法的成功延续。
-- | Local Snap monad version of 'modify'. smodify :: (SnapState -> SnapState) -> Snap () smodify f = Snap $ \sk _ st -> sk () (f st) {-# INLINE smodify #-}
modifyResponse
将smodify
从Snap 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 #-}