haskell - monad 变压器何时需要提升?

标签 haskell monads monad-transformers lifting

我正在学习单子(monad)更改器(mutator),我对何时需要使用电梯感到困惑。
假设我有以下代码(它没有做任何有趣的事情,只是我可以用来演示的最简单的代码)。

foo :: Int -> State Int Int
foo x = do
  (`runContT` pure) $ do
    callCC $ \exit -> do
      when (odd x) $ do
        -- lift unnecessary
        a <- get
        put $ 2*a
      when (x >= 5) $ do
        -- lift unnecessary, but there is exit 
        a <- get
        exit a
      when (x < 0) $ do
        -- lift necessary
        a <- lift $ foo (x + 10)
        lift $ put a

      lift get

所以有一个 monad 堆栈,其中 main do block 的类型为 ContT Int (StateT Int Identity) Int .

现在,在第三个 when do block with recursion 编译程序需要一个提升。在第二个街区,不需要电梯,但我不知何故认为这是因为 exit 的存在。以某种方式强制将线上方的线提升到 ContT .但在第一个街区,不需要电梯。 (但如果明确添加,也没有问题。)这真的让我很困惑。我觉得所有的when do block 是等效的,无论在任何地方都应该需要电梯。但这显然不是真的。需要/不需要电梯的关键区别在哪里?

最佳答案

由于您使用的 monad 转换器库有点聪明,因此这里出现了困惑。具体来说,get 的类型和 put没有明确提及 StateStateT .相反,它们是沿线的

get :: MonadState s m => m s
put :: MonadState s m => s -> m ()

因此,只要我们在带有 MonadState 的上下文中使用它实现 monad 不需要显式 lift s。在您使用 get 的所有实例中都是这种情况。/put自从
instance MonadState s (StateT s m)
instance MonadState s m => ContT k m

两者都持有。换句话说,类型类解析将自动为您处理适当的提升。这反过来意味着您可以省略 liftget/put在你的程序结束时。

递归调用不会发生这种情况,因为它的类型是明确的 State Int Int .如果将其概括为 MonadState Int m => m Int你甚至可以省略这最后的电梯。

关于haskell - monad 变压器何时需要提升?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45236226/

相关文章:

arrays - 当 Data.Vector.unfoldr 不融合时会发生什么?

haskell - DefaultSignatures 和相关的类型族

haskell - 状态单子(monad) haskell

haskell - 提升以固定单子(monad)变压器堆栈的“内部”

haskell - 在 Haskell 中实现按值调用 lambda 演算

haskell - GHC 包冲突

haskell - 结合 StateT 和 State monad

haskell - Haskell 中状态单子(monad)的增量函数

haskell - 将数据类型定义为 MonadSample

haskell - 从分类的角度看,Haskell 的 monad 转换器是什么?