查看包loops
,我发现它非常有趣并且可能有用。但是,关于包装的一部分我不明白:我应该如何使用break_
?
我们假设我有一个函数get' :: IO (Maybe Int)
,每次调用都会返回一个从文件中读取的数字,如果达到了EOF,则返回Nothing
。我试图构建一个简单的循环,我打印每个数字并打破EOF。
现在,我知道无限循环我可以使用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
但我在哪里放break_
?它是LoopT IO Int
,所以我只能把它放在LoopT
monad中,但它不应该被称为中间交互,而不是在定义循环时?这真让我困惑。
答案 0 :(得分:4)
LoopT
是monad transfomer,因此您需要liftIO
print x
声明。
以下是一些使用示例:
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_
<强>更新强>
如果你想在另一个monad中执行无限循环,我只会使用forever
中的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
更新2
另一个使用monadic条件的例子:
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 ()
当然,这个循环并没有返回最喜欢的数字 - 它只是一直询问,直到用户回答&#34;是&#34;。
答案 1 :(得分:2)
这是您的循环直接转换为loops
样式:
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)