How do I use `break_` in the package “loops”?

五迷三道 提交于 2020-01-15 09:13:21

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!