【问题标题】:How to read three consecutive integers from stdin in Haskell?如何从 Haskell 的标准输入中读取三个连续的整数?
【发布时间】:2017-02-15 15:06:12
【问题描述】:

我想使用 Haskell 将12 34 56 之类的输入读入三个整数。

对于单个整数,可以使用myInteger <- readLn。但是对于这种情况,我没有找到任何解决方案,除了首先读取一行,然后用,替换所有空格,(使用类似:

spaceToCommas str =
  let repl ' ' = ','
      repl  c =   c
  in map repl str

) 然后打电话给read '[' ++ str ++ ']' 感觉很hackish。此外,它不允许我声明我要读取 三个 整数,它会尝试从标准输入读取 任何 个整数。

必须有更好的方法。

请注意,我想要一个依赖外部包的解决方案。使用例如Parsec 当然很棒,但是这个简单的例子应该不需要使用成熟的 Parser Combinator 框架,对吧?

【问题讨论】:

  • 为什么不在一个do-block中调用readLn 3次呢?或者使用具有副作用的映射,映射长度为 3 的范围,然后在函数内部调用 readLn。这将返回一个包含 3 个整数的列表。
  • 你想从一行中读取 3 个整数吗?输入通常是行缓冲的——如果单行上有 4 个整数怎么办?如果只有 2 个呢?
  • 哦,你想读一行吗?为什么不直接读进去然后按空格分开?
  • @Carcigenicate 是的,来自一行。如果它们在多行上,那么您的解决方案确实是简单而完美的。
  • 记住你从不读3个整数;你总是读一个字符串。然后需要解析该字符串,其范围可以从微不足道(如果您只期望具有 Read 实例的类型的单个值)到复杂。

标签: haskell io-monad


【解决方案1】:

像这样转换字符串呢:

convert :: Read a => String -> [a]
convert = map read . words

words 将给定字符串拆分为字符串列表(“单词”),然后我们使用map 对每个元素执行read

例如像这样使用它:

main = do
    line <- getLine
    let [a,b,c] = convert line :: [Int] in putStrLn (show (c,a,b))

或者,例如,如果您想阅读前三个元素而不关心其余部分(是的,这显然需要超级-创造力技能):

main = do
    line <- getLine
    let (a:b:c:_) = convert line :: [Int] in putStrLn (show (c,a,b))

我这里返回了一个元组,它向右旋转了一个位置以显示解析完成。

【讨论】:

  • 这不会从标准输入读取 3 个整数,这只是抓取一行,尝试读取所有内容,如果不完全是三个,则会失败并出现模式匹配错误。 (“另外,它不允许我声明我想读取三个整数,它会尝试从标准输入读取任意数量的整数。”)
  • @user2407038:不,它本身并不会尝试读取所有内容,因为map 是惰性的(并且map 的元素上的f x 也是惰性的),此外还有一个一点点创意你当然可以用两个、四个或任意数量的整数来实现场景:)。
  • 如何在模式匹配中正确使用它?尝试使用case convert line of 时,我总是得到*** Exception: user error (Prelude.readIO: no parse)
  • 我遇到的问题与我的代码中的其他内容有关
最近更新 更多