在尝试为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之后,我发现了shiftTresetTthis 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/

10-11 15:15