Haskell IO的多行读取技术

Haskell IO的多行读取技术,haskell,io,Haskell,Io,基本上,我想找到一种方法,让用户可以输入测试用例的数量,然后输入他们的测试用例。然后,程序可以运行这些测试用例,并按照测试用例出现的顺序打印结果 所以基本上我有main,它读取测试用例的数量,并将它输入到一个函数中,这个函数将从IO读取很多次。看起来是这样的: main = getLine >>= \tst -> w (read :: String -> Int) tst [[]] 这是w:w::Int->[[Int]]->IO() 因此,我的计划是读取测试用例的数量,

基本上,我想找到一种方法,让用户可以输入测试用例的数量,然后输入他们的测试用例。然后,程序可以运行这些测试用例,并按照测试用例出现的顺序打印结果

所以基本上我有main,它读取测试用例的数量,并将它输入到一个函数中,这个函数将从IO读取很多次。看起来是这样的:

main = getLine >>= \tst -> w (read :: String -> Int) tst [[]]
这是w:
w::Int->[[Int]]->IO()


因此,我的计划是读取测试用例的数量,让w运行一个函数,该函数接收每个测试用例,并将结果存储到[[]]变量中。因此,列表中的每个列表都将是一个输出。w将递归运行,直到它达到0,并在单独的一行上打印每个列表。我想知道是否有更好的方法来实现这一点,因为我必须将一个空列表传递到w,这似乎是无关的。

正如@bheklillr提到的,您不能更新像
[[]]
这样的值。标准的函数方法是通过一组递归调用传递累加器。在下面的示例中,
循环
函数的
acc
参数是这个累加器-它包括迄今为止收集的所有输出。在循环结束时,我们返回它

myTest :: Int -> [String]
myTest n = [ "output line " ++ show k ++ " for n = " ++ show n | k <- [1..n] ]

main = do
  putStr "Enter number of test cases: "
  ntests <- fmap read getLine :: IO Int
  let loop k acc | k > ntests = return $ reverse acc
      loop k acc = do
        -- we're on the kth-iteration
        putStr $ "Enter parameter for test case " ++ show k ++ ": "
        a <- fmap read getLine :: IO Int
        let output = myTest a         -- run the test
        loop (k+1) (output:acc)
  allOutput <- loop 1 []
  print allOutput

使用
fmap
可以消除中间变量
line
,我们无论如何都不会再引用它。我们仍然需要提供类型签名,以便
read
知道该做什么。

惯用的方法是使用
replicitem

runAllTests :: [[Int]] -> IO ()
runAllTests = {- ... -}

main = do
    numTests <- readLn
    tests <- replicateM numTests readLn
    runAllTests tests
-- or:
-- main = readLn >>= flip replicateM readLn >>= runAllTests
runAllTests::[[Int]]->IO()
runAllTests={-…-}
main=do
numTests=flip replictem readLn>>=runAllTests

将结果存储在
[[]]
变量中是什么意思<代码>[[]]不是一个变量,它是一个不可变的值,就像所有其他Haskell值一样。如果要读取特定数量的行,可以使用
Control.Monad.replicItem n getLine
,其中
n
是要读取的行数。因此,我会继续将结果附加到列表列表中,并在最后打印出所有结果。我不知所措,因为我无法同时返回列表列表和使用IO()类型。我是否应该执行类似于
fmap read$words getLine::[IO Int]
?谢谢。关于
:IO[Int]
部分的问题。我如何解释它?是不是说fmap会返回IO[Int]信息?然后我们使用正确的
。我已经更新了答案来帮助解释fmap是如何工作的。非常感谢。如果可以的话,还有一个问题,
(map read.words)
要映射到getLine的函数是什么?我将如何解释
地图阅读。单词
?它是否需要一些[Char]输入,然后将其更改为[[Char]],并在其上进行读取映射?
runAllTests :: [[Int]] -> IO ()
runAllTests = {- ... -}

main = do
    numTests <- readLn
    tests <- replicateM numTests readLn
    runAllTests tests
-- or:
-- main = readLn >>= flip replicateM readLn >>= runAllTests