问题
Looking into the package loops, I found it very interesting and could be useful. However, there's one part about the package that I don't understand: how am I supposed to use break_?
Let's say I have a function get' :: IO (Maybe Int)
, with which each call will return a number read from a file, and returns Nothing
if the EOF is reached. I'm trying to construct a simple loop where I print each number and break upon EOF.
Now, I know to loop indefinitely I can use forever
:
import Control.Monad.Loop as ML
import Control.Monad as M
main = do
M.sequence . loop $ do
ML.forever
return $ do
mx <- get'
case mx of
Nothing -> ???
Just x -> print x
But where do I put my break_
? It is a LoopT IO Int
, so I can only put it in LoopT
monad, but isn't it supposed to be called mid interation, instead of when defining loops? This really confuses me.
回答1:
LoopT
is a monad transfomer, so you will need to liftIO
your print x
statement.
Here are some usage examples:
import Control.Monad
import Control.Monad.Trans (liftIO)
import Control.Monad.Loop as ML
-- infinite printing loop
foo :: LoopT IO ()
foo = do
x <- ML.iterate 0 (+1)
liftIO $ print x
run_foo = ML.exec_ foo
-- prints 1, 3, 5, 7, 9
bar :: IO ()
bar = ML.exec_ $ do
x <- ML.iterate 1 (+2)
if x < 10
then liftIO $ print x
else break_
Update
If you want to execute a infinite loop in another monad, I would just use forever
from Control.Monad
--
import Control.Monad
import Control.Monad.State
myloop = forever $ do
x <- get
liftIO $ print x
put (x+1)
main = runStateT myloop 10 -- start loop at 10
Update 2
Another example using a monadic condition:
findFavoriteNumber = ML.exec_ $ do
x <- ML.iterate 1 (+1)
yn <- liftIO $ do putStr $ "is " ++ show x ++ " your favorite number? "
getLine
if yn == "yes"
then break_
else return ()
Of course, this loop doesn't return the favorite number - it just keeps asking until the user responds with "yes".
回答2:
Here's a direct translation of your loop to loops
style:
module Main where
import Control.Monad.Loop as ML
import Text.Read (readMaybe)
import Control.Exception
import System.IO.Error
import Control.Applicative
import Control.Monad.IO.Class
get' :: IO (Maybe Int)
get' = do
catchJust (\e -> if isEOFError e then Just () else Nothing)
(return . readMaybe =<< getLine)
(const $ return Nothing)
main :: IO ()
main = exec_ $
ML.forever >> do
mx <- liftIO get'
case mx of
Nothing -> break_
Just x -> liftIO (print x)
来源:https://stackoverflow.com/questions/32918416/how-do-i-use-break-in-the-package-loops