我正在学习单子变换器,我对何时需要使用电梯感到困惑。假设我有以下代码(它没有做任何有趣的事情,只是我可以用来演示的最简单的代码)。
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
所以有一个单子堆栈,其中主要的 do 块有类型ContT Int (StateT Int Identity) Int
。
现在,在第三个when
带递归的 do 块中,程序编译需要一个提升。在第二个街区,不需要电梯,但我不知何故认为这是因为它的存在以exit
某种方式迫使线上方的线被提升到ContT
. 但在第一个街区,不需要电梯。(但如果明确添加,也没有问题。)这真的让我很困惑。我觉得所有的when
do 块都是等效的,无论在任何地方都应该需要电梯。但这显然不是真的。需要/不需要电梯的关键区别在哪里?