2016-07-11 2 views
1

HaskellでgetInt :: IO Int関数を使用したいと考えています。これは、stdinから整数を取って残りのバッファをそのまま残す関数です。それは全体のライン3 4を取るので代わりに3を取り、4を残す、HaskellにgetInt関数がありますか?

2 
3 4 

私が発見したこのタイプのライブラリ関数は、readLn :: IO Intは、例えば、などの入力では動作しません次はgetIntです。私は完全な文字列を読み取ってからwordsを使って分割することができますが、バッファを消費しない方法があるかどうか尋ねたいと思います。

これを実行する標準ライブラリには何らかの機能がありますか?私は行方不明ですgetIntを作成するためのシンプルで明白な方法はありますか?

+1

'Int'sの間に区切り文字を使用しても問題ありませんか?もしそうなら、あなたはセパレータを見るまで 'getChar'を呼び出すループを調理し、結果の' String'に対して 'readIO'を呼び出すのは簡単です。 –

+0

「getLine」実装(?)で ''やそれに類するものの '\ n'を変更するのはどうでしょうか?http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC .IO.Handle.Text.html#hGetLine –

+0

これは本質的に私が記述したものですが、まず、標準的な 'getLine'実装のバッファリング認識の虚栄をすべてスキップすることをお勧めします。 –

答えて

2

元のアスカーは消費セパレータと大丈夫であるようですので、ここで私は、答えに私のコメントを回します。まず、getLineと類似のgetWordを定義します。その後我々は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秒または他の複雑なデータ型のように)それらのスペースを持って読まれるべき値ではうまく機能しませ。

+1

EOFに遭遇したらどうなりますか?これを強く行うために、あなたは 'hLookAhead'を使う必要があると思います。 – ErikR

+0

@ErikR EOFをうまく処理するために 'getWord'を更新しました。 –

+0

handleJust(guard.isEOFError)(\() - を使用して 'handleJust :: Exception e =>(e - >多分b) - >(b - > IO a) - > IO a - > IO a ' > return [])$ do ... '? – dfeuer

0

hLookAheadを使用し、isEOFErrorをキャッチすると、このような関数を書くことができます。しかし、IOをあなたの解析と混在させます。

よりHaskellishソリューションを定義することです。その後、

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

と、このようなparseInts使用:

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

(例:のようなファイルを解析するには

-- 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 =列数)、オプションの束:

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... 
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 
+0

ちなみに、 'withCString "%d" $ \ str - > 0 $ \ i - > c_scanf str i >> peek iは 'scanf("%d "、%i)'と同じ動作をします。しかし、それは単なる楽しいものであり、他のHaskellの関数と混同すべきではありません。 – Zeta

+0

'hLookAhead'をうまく使います。おそらく 'isEOF'をチェックするべきでしょうか? – chi

関連する問題