在尝试为 ContT monad 转换器建立一些直觉时,我(也许并不奇怪)发现自己很困惑。问题在于 shiftT 操作似乎没有做任何有用的事情。
首先是一个如何使用它的简单示例
shiftT $ \famr -> lift $ do
a <- calculateAFromEnvironment
famr a
famr a
可以是一些更复杂的表达式,只要它返回一些m r
。现在尝试解释我的直觉,shiftT 并没有添加任何内容:
-- inline shiftT
ContT (\f2 -> evalContT ((\f1 -> lift (do
a <- calculateAFromEnvironment
f1 a)) f2))
-- beta reduction
ContT (\f2 -> evalContT (lift (do
a <- calculateAFromEnvironment
f2 a)))
-- inline evalConT
ContT (\f2 -> runContT (lift (do
a <- calculateAFromEnvironment
f2 a)) return)
-- inline lift
ContT (\f2 -> runContT (ContT (\f3 -> (do
a <- calculateAFromEnvironment
f2 a) >>= f3)) return)
-- apply runConT
ContT (\f2 -> (\f3 -> (do
a <- calculateAFromEnvironment
f2 a) >>= f3) return)
-- beta reduce
ContT (\f2 -> (do
a <- calculateAFromEnvironment
f2 a) >>= return)
-- (>>= return) is identity
ContT $ \f2 -> do
a <- calculateAFromEnvironment
f2 a
事实证明我们可以直接构建 ContT。
提问时间:是否存在shift/shift在cont/ContacT之上添加任何内容的情况?或者它们只是用来使代码更具可读性?
After by 古尔肯格拉斯 https://stackoverflow.com/users/5318306/gurkenglas我发现的建议这个很好的解释 https://github.com/renormalist/pugs/blob/f09558ae9b5ef2cbab75110abc1cb385931329cc/src/Pugs/AST/Eval.hs#L27 of shiftT
and resetT
带有用法、动机和语义的示例!
这些功能非常简单。他们的定义在transformers http://hackage.haskell.org/package/transformers-0.5.4.0/docs/Control-Monad-Trans-Cont.html#v:shiftT库很简单:
resetT :: (Monad m) => ContT r m r -> ContT r' m r
resetT = lift . evalContT
shiftT :: (Monad m) => ((a -> m r) -> ContT r m r) -> ContT r m a
shiftT f = ContT (evalContT . f)
但哲学和意义远远落后于一些直观的理解。所以我建议您阅读上面链接中的解释。有时,很容易定义的事情实际上可以做一些复杂的事情。
根据上面链接的 pugs 中的解释改编的文档:
shiftT
shiftT
就好像callCC
,除了当您激活延续时
由...提供shiftT
,它将运行到最近的封闭的末尾resetT
,
然后跳回到您激活延续的点之后。
请注意,因为控制最终返回到
子延续已激活,您可以在中多次激活它
同一个块。这与callCC
的延续,丢弃当前的
激活时的执行路径。
See resetT
有关这些分隔子延续实际上如何的示例
工作。
resetT
创建一个范围shiftT
的子延续最终保证
退出结束。考虑这个例子:
resetT $ do
alfa
bravo
x <- shiftT $ \esc -> do -- note: esc :: m Int, not a ContT
charlie
lift $ esc 1
delta
lift $ esc 2
return 0
zulu x
这会:
Perform alfa
Perform bravo
Perform charlie
Bind x
为 1,从而执行zulu 1
从末端掉下来resetT
,然后跳回到刚刚之后esc 1
Perform delta
Bind x
到 2,从而执行zulu 2
从末端掉下来resetT
,然后跳回到刚刚之后esc 2
逃离resetT
,导致其产量为 0
因此,不同于callCC
的延续,这些子延续最终将
在它们被激活后返回到点,在从末端掉落后
最近的resetT
.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)