Haskell上有getInt函数吗?

时间:2016-07-11 18:15:25

标签: haskell io

我想在Haskell上有一个getInt :: IO Int函数。这将是一个从 stdin 获取整数的函数,保留缓冲区的其余部分。

我发现的这种类型的库函数,例如readLn :: IO Int,不能用于输入:

2
3 4

因为它需要整行3 4,而不是将34留给下一个getInt。虽然我知道我可以读取完整的字符串,然后使用words将其拆分,但我想问一下是否有一种不消耗缓冲区的方法。

标准库是否有任何功能?是否有任何简单/明显的方法来创建我遗失的getInt

4 个答案:

答案 0 :(得分:3)

在这里,我将我的评论转化为答案,因为看起来原始的提问者可以使用分隔符。首先,我们将getWord模拟定义为getLine;然后我们将readIO结果。我们将小心捕捉EOF例外情况。

import Control.Exception
import Control.Applicative
import Data.Char
import System.IO.Error

getWord :: IO String
getWord = handle handleEOF $ do
  c <- getChar
  if isSpace c then return [] else (c:) <$> getWord
  where
  handleEOF e = if isEOFError e then return [] else throwIO e

readWord :: Read a => IO a
readWord = getWord >>= readIO

注意:这当然不适用于要读取的有空格的值(如Data.Map s或其他复杂数据类型)。

答案 1 :(得分:2)

  

是否有任何简单/明显的方法可以创建我缺少的getInt?

没有。没有一个。你正在寻找scanf("%d")之外的东西,它会忽略所有前导空格,如果没有数字则不会更改缓冲区。在这种情况下你需要展望未来:

import Data.Char (isSpace, isDigit, digitToInt)
import Data.List (foldl')
import Control.Monad (when)
import System.IO (hGetChar, hLookAhead, Handle, stdin)

getInt :: IO (Maybe Int)
getInt = hGetInt stdin

hGetIntegral :: (Integral n) => Handle -> IO (Maybe n)
hGetIntegral h = do 
  hSkipSpace h
  digits <- hGetDigits h
  return $ case digits of
    [] -> Nothing
    xs -> Just $ foldl' (\x a -> 10 * a + x) 0 . map digitToInt $ xs

hGetDigits :: Handle -> IO [Char]
hGetDigits h = do
  la <- hLookAhead h
  if isDigit la then hGetChar h >> fmap (la:) (hGetDigits h)
                else return []

hSkipSpace :: Handle -> IO ()
hSkipSpace h = do
  la <- hLookAhead h
  when (isSpace la) $ hGetChar h >> hSkipSpace h

答案 2 :(得分:0)

您可以使用hLookAhead编写此类函数并捕获isEOFError。但是,您将IO与解析混合在一起。

更多Haskellish解决方案是定义:

parseInts :: String -> [Int]
parseInts str = map read (words str)

然后像这样使用parseInts

-- read an entire file and convert to a list of Ints
nums <- fmap parseInts getContents


-- read just a line and convert to a list of Ints
nums <- fmap parseInts getLine

解析看起来像的文件:

3 4
1 1 1 1
2 2 2 2 
3 3 3 3

(例如3 =行数,4 =列数),你有很多选择:

import Control.Monad (replicateM)

main = do
  (nrows : ncols : _) <- fmap parseInts getLine
  rows <- replicateM nrows $ fmap parseInts getLine

import Data.List.Split (chunksOf)

main = do
  (nrows : ncols : rest) <- fmap parseInts getContents
  let rows = chunksOf ncols rest

甚至:

main = do
  (nrows : ncols : _) <- fmap parseInts getLine
  forM_ [1..nrows] $ \i -> do
    row <- fmap parseInts getLine
    ... do something with row...

答案 3 :(得分:0)

readInt :: [Char] -> Maybe Int
readInt [] = Nothing
readInt str = case reads str :: [(Int, String)] of
    [(x ,"")] -> (Just x)
    _ -> Nothing

getInt :: IO (Maybe Int)
getInt = do
    nums <- getLine
    return (readInt nums)

在这里,您可以根据需要将可能的食物带出一个合适的地方,或者通过修改将其取走

,勇敢的勇气