如何在包 "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)