如何在包 "loops" 中使用 `break_`?
How do I use `break_` in the package "loops"?
查看包裹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_
?
假设我有一个函数 get' :: IO (Maybe Int)
,每次调用都会 return 从文件中读取一个数字,如果 EOF 是 returns 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中,但它不是应该被称为mid interation,而不是定义循环时吗?这真的让我很困惑。
LoopT
是一个单子变换器,因此您需要 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
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
更新 2
另一个使用单子条件的例子:
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 ()
当然,此循环不会 return 最喜欢的号码 - 它只是不断询问,直到用户用 "yes" 响应。
这是将您的循环直接翻译成 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)
查看包裹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_
?
假设我有一个函数 get' :: IO (Maybe Int)
,每次调用都会 return 从文件中读取一个数字,如果 EOF 是 returns 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中,但它不是应该被称为mid interation,而不是定义循环时吗?这真的让我很困惑。
LoopT
是一个单子变换器,因此您需要 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
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
更新 2
另一个使用单子条件的例子:
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 ()
当然,此循环不会 return 最喜欢的号码 - 它只是不断询问,直到用户用 "yes" 响应。
这是将您的循环直接翻译成 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)