继续使用延续monad

Bob*_*Bob 13 monads continuations haskell functional-programming monad-transformers

可以使用continuation monad在程序中向后跳转:

{-# LANGUAGE RecursiveDo #-}

import Control.Monad.Fix
import Control.Monad.Trans.Cont

setjmp = callCC (\c -> return (fix c))

backward = do
  l <- setjmp
  -- some code to be repeated forever
  l
Run Code Online (Sandbox Code Playgroud)

但是当我试图向前跳时,GHC不接受它:

forward = mdo
  l
  -- some dead code
  l <- setjmp  
  return ()
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为没有为其定义MonadFix (ContT r m)的continuation monad转换器的实例.有关详细信息,请参阅Levent Erkok论文的第5.1节.ContTControl.Monad.Trans.Cont

有没有一种方法来编码前向跳转而没有值继续monad的值递归?

是否有一个替代定义ContT有一个实例MonadFix (ContT r m)?Magnus Carlsson 有一份未发表的草案提出了这样的建议,但我不知道该怎么办.

ben*_*ofs 7

如果你将死代码移到里面callCC,你可以这样做,如下所示:

import Control.Monad.Cont

forward :: ContT () IO ()
forward = do
  callCC $ \skip -> do
    skip ()
    lift $ putStrLn "This is not executed"
  lift $ putStrLn "Control flow continues here"

main :: IO ()
main = runContT forward return
Run Code Online (Sandbox Code Playgroud)

不可能完全按照自己的意愿行事.要了解原因,请考虑以下示例:

mdo
  l
  c <- lift getChar
  l <- if c == 'a' then setjmp else return (return ())
  lift $ putStrLn "end"
Run Code Online (Sandbox Code Playgroud)

这应该怎么办?


您也可以稍后跳回到跳过的代码.您只需将延续传递给您跳过的代码即可.使用您的示例,goto L2: L1: some code; goto END; L2: goto L1; END: return可以实现为:

import Control.Monad.Cont

forward :: ContT () IO ()
forward = do
  callCC $ \end -> do
    l1 <- callCC $ \l2 -> do
      callCC $ \l1 -> l2 l1
      liftIO $ putStrLn "In L1"
      end ()
    liftIO $ putStrLn "In L2"
    l1 ()
  liftIO $ putStrLn "End"

main :: IO ()
main = runContT forward return
Run Code Online (Sandbox Code Playgroud)

在这里,我们将延续传递给我们跳过的部分(l1)返回到外部代码,以便它可以跳转到那里.