[英]Jumping forward with the continuation monad
可以使用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
但是當我試圖向前跳時,GHC不接受它:
forward = mdo
l
-- some dead code
l <- setjmp
return ()
這不起作用,因為在Control.Monad.Trans.Cont
定義的連續monad變換器ContT
沒有MonadFix (ContT rm)
實例。 有關詳細信息,請參閱Levent Erkok論文的第5.1節。
有沒有一種方法來編碼前向跳轉而沒有值繼續monad的值遞歸?
是否存在具有ContT
實例MonadFix (ContT rm)
的ContT
的替代定義? Magnus Carlsson有一份未發表的草案提出了這樣的建議,但我不知道該怎么辦。
如果你在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
不可能完全按照自己的意願行事。 要了解原因,請考慮以下示例:
mdo
l
c <- lift getChar
l <- if c == 'a' then setjmp else return (return ())
lift $ putStrLn "end"
這應該怎么辦?
您也可以稍后跳回到跳過的代碼。 您只需將延續傳遞給您跳過的代碼即可。 使用您的示例, goto L2: L1: some code; goto END; L2: goto L1; END: return
goto L2: L1: some code; goto END; L2: goto L1; END: return
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
在這里,我們將繼續傳遞給我們跳過的部分( l1
)回到外部代碼,以便它可以跳轉到那里。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.