在尝试为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/shiftT在cont/ContT之上添加任何内容的情况?还是只是用来使代码更具可读性?
最佳答案
根据searching github的建议使用Gurkenglas之后,我发现了shiftT
和resetT
的this very nice explanation以及用法,动机和语义示例!
这些功能非常简单。它们在 transformers
库中的定义很简单:
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)
但是哲学和意义远远落后于一些直观的理解。因此,我建议您阅读上面的链接中的说明。有时候,容易定义的事情实际上可以做一些复杂的事情。
根据上面链接的哈巴狗中的解释改编了文档:
关于haskell - 连续单向移位,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43695653/