繁体   English   中英

在得到结果之前,如何永久重试 IO?

[英]How can I perpetually retry an IO until I get a result?

我正在尝试从命令行提示符读取 integer 并且我希望我的程序一直要求输入,直到它可以解析正确的值。

这就是我想出的

import Control.Exception
import System.IO

prompt :: String -> IO String
prompt text = do
  putStr text
  hFlush stdout
  getLine

getInt :: IO Int
getInt = handle recoverError readParse
  where recoverError :: SomeException -> IO Int
        recoverError _ = getInt
        readParse = fmap read $ prompt ">> "

main :: IO ()
main = fmap show getInt >>= putStrLn

我希望handle function 在出现read Exception时递归调用getInt ,但显然情况并非如此。

这是我执行这个程序时看到的

$ ./main
>> 10
10

$ ./main
>> not a number
main: Prelude.read: no parse

我是 haskell 的新手,所以可能在这里遗漏了一些明显的东西。

任何帮助表示赞赏。

问题在于,由于 Haskell 的懒惰, readParse不会出现read异常。 直到 putStrLn show n 字符串为putStrLn时才会评估read结果,然后才会发生异常。

您可能可以通过使用来解决此问题evaluate ,但这里的正确解决方案是根本不依赖异常:

如果解析不成功, read失败并出现error ,因此不鼓励在实际应用程序中使用它。 使用readMaybereadEither以获得安全的替代方案。

getInt :: IO Int
getInt = maybe getInt return =<< readMaybe <$> prompt ">> "
-- alternatively written as
getInt = do
  input <- prompt ">> "
  case readMaybe input of
    Just v  -> return v
    Nothing -> getInt

使用readIO而不是read ,如:

readParse = prompt ">> " >>= readIO

不同之处在于fmap read创建了一个 IO 操作,该操作始终成功并产生带有嵌入异常的纯结果,而readIO创建一个 IO 操作,该操作可能会引发 IO 异常,但其纯值始终成功您也可以将getLinereadIO结合使用,改为使用readLn ,如下所示:

prompt :: Read a => String -> IO a
prompt text = do
  ...
  readLn

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM