Almost literal, not elegant, but effective translation.
We use a ContT monad transformer to achieve an early return effect. Ie, we want to be able to break our loops at any moment. This is achieved using callCC $ \exit -> ... , which roughly makes exit our magic function, which allows us to leave the internal blocks immediately.
import Control.Monad.Cont action :: IO String action = flip runContT return $ callCC $ \exit -> forever $ do -- while (true) let loop = do r1 <- lift $ get -- if (get()) when r1 $ do r2 <- lift $ put1 when r2 $ -- if (put1()) exit "failImmediately" loop -- "repeat while" loop r3 <- lift $ put2 when r3 $ exit "succeedImmediately" get :: IO Bool get = readLn put1 :: IO Bool put1 = putStrLn "put1 here" >> readLn put2 :: IO Bool put2 = putStrLn "put2 here" >> readLn main :: IO () main = action >>= putStrLn
We can also define some custom helpers to prefix the code:
action2 :: IO String action2 = flip runContT return $ callCC $ \exit -> forever $ do -- while (true) whileM get $ -- while(get()) whenM put1 $ -- if (put1()) exit "failImmediately" whenM put2 $ -- if (put2()) exit "succeedImmediately" whenM :: (MonadTrans t, Monad m, Monad (tm)) => m Bool -> tm () -> tm () whenM condition a = do r <- lift condition when ra whileM :: (MonadTrans t, Monad m, Monad (tm)) => m Bool -> tm () -> tm () whileM condition a = whenM condition (a >> whileM condition a)
source share