如何在haskell中的一行中输入多个值

时间:2014-02-19 15:49:40

标签: haskell

例如,我想编写一个程序,它将从命令行输入3个整数。我学到的函数是readLn来读取整行的值。但readLn似乎将整行解析为单个值。如何使用haskell获取一行的三个值?

3 个答案:

答案 0 :(得分:14)

使用getLine阅读一行,将其分为words和每个read

readInts :: IO [Int]
readInts = fmap (map read.words) getLine

它读取任意数量的Ints:

ghci> readInts
1 2 3
[1,2,3]
ghci> readInts
1 2 3 4 5 6
[1,2,3,4,5,6]

你可以限制为三个:

read3Ints :: IO [Int]
read3Ints = do
     ints <- readInts
     if length ints == 3 then return ints else do
         putStrLn ("sorry, could you give me exactly three integers, "
                  ++ "separated by spaces?")
         read3Ints

看起来像这样:

ghci> read3Ints
1 2
sorry, could you give me exactly three integers, separated by spaces?
1 23 , 5, 6
sorry, could you give me exactly three integers, separated by spaces?
1,2,3
sorry, could you give me exactly three integers, separated by spaces?
1 3 6

fmap

的秘密

fmap有点像map,但您可以更广泛地使用它:

ghci> fmap (*10) [1,2,3,4]
[10,20,30,40]
ghci> fmap (*10) (Just 5)
Just 50
ghci> map (fmap (*10)) [Left 'b', Right 4, Left 'c', Right 7]
[Left 'b',Right 40,Left 'c',Right 70]
ghci> fmap words getLine
Hello there me hearties!
["Hello","there","me","hearties!"]

getInts中,我fmap (map read.words)按行分隔行,然后map read将每行分成Int。由于类型签名,编译器知道我想要Int - 如果我省略它,我会收到错误。

答案 1 :(得分:2)

有几种方法可以解决这个问题,但我更喜欢使用reads的方法。此函数的类型为Read a => ReadS a,其中ReadS a只是String -> [(a, String)]的类型别名。它从提供的字符串中提取字符,在不再成功解析时停止,然后返回包含已解析值的元组和剩余字符串的列表。它使用一个列表来获得更灵活的定义,但实际上你永远不会看到它返回一个超过1个元素的列表。一个例子是

> reads "1 2 3" :: [(Int, String)]
[(1, " 2 3")]
> reads " 2 3" :: [(Int, String)]
[(2, " 3")]

使用此函数,我们可以解析Int的一行,当它无法解析一个或字符串为空时它会自动停止。我们只需要一种将多个呼叫链接在一起的方法。理想情况下,我们想要一个(s -> [(a, s)]) -> s -> [a]类型的函数,以便我们可以重复使用它:

chain :: (s -> [(a, s)]) -> s -> [a]
chain f s = case f s of
    [] -> []
    [(a, newS)] -> a : chain f newS
    xs -> map fst xs ++ chain f (last $ map snd xs)

然后你可以用它作为

> chain reads "1 2 3" :: [Int]
[1, 2, 3]
> chain reads "1 2 3 asdf" :: [Int]
[1, 2, 3]
> chain reads "asdf 1 2 3" :: [Int]
[]

然后你只需做

read3Ints :: String -> [Int]
read3Ints = take 3 . chain reads

答案 2 :(得分:1)

怎么样:

    getInts::[Int]
    getInts = do s<-getLine
                 map read . words $ s