Haskell:打印案例编号

时间:2016-12-01 02:28:28

标签: haskell

我编写了一个Haskell代码:

loop = do
 x <- getLine
 if x == "0"
  then return ()
  else do arr <- replicateM (read x :: Int) getLine 
          let blocks = map (read :: String -> Int) $ words $ unwords arr
          putStr "Case X : output = "; -- <- What should X be?
          print $ solve $ blockPair blocks;
          loop

main = loop

终止于0输入。我还想打印案例编号,例如。 Case 1, 2 ...

示例运行:

1
10 20 30
Case 1: Output = ...
1
6 8 10
Case 2: Output = ...
0 

有谁知道如何做到这一点?另外,如果可能的话,你可以建议我在最后打印输出线吗?

提前致谢。

2 个答案:

答案 0 :(得分:3)

对于问题的第一部分,当前案例编号是某些&#34;州&#34;的示例。您希望在程序执行过程中保持这种状态。在其他语言中,毫无疑问,您使用可变变量。

在Haskell中,有几种方法可以处理状态。其中一个最简单的(虽然它有时有点难看)是将状态明确地作为函数参数传递,并且考虑到您已经构建代码的方式,这将非常有效:

main = loop 1

loop n = do
  ...
  putStr ("Case " ++ show n ++ ": Output = ...")
  ...
  loop (n+1)  -- update "state" for next loop

你的问题的第二部分涉及更多一点。看起来你想要一个提示而不是一个解决方案。为了帮助您入门,让我向您展示一个函数示例,该函数在用户输入end之前读取行,然后返回所有行的列表,但不包括end(以及{使用大多数纯代码的行做一些有趣的函数:

main

编辑:我想你想要一个更直接的答案而不是一个提示,所以你采用上述方法来阅读一个块列表的方式就是写下这样的东西:

readToEnd :: IO [String]
readToEnd = do
    line <- getLine
    if line == "end"
      then return []
    else do
      rest <- readToEnd
      return (line:rest)

main = do
    lines <- readToEnd
    -- now "pure" code makes complex manipulations easy:
    putStr $ unlines $
      zipWith (\n line -> "Case " ++ show n ++ ": " ++ line)
              [1..] lines

然后readBlocks :: IO [[Int]] readBlocks = do n <- read <$> getLine if n == 0 then return [] else do arr <- replicateM n getLine let block = map read $ words $ unwords arr blocks <- readBlocks return (block:blocks) 看起来像这样:

main

答案 1 :(得分:0)

这在精神上类似于K. A. Buhr的答案(关键的举动仍然是将状态作为参数传递),但是以不同的方式来证明一个巧妙的技巧。由于IO操作只是普通的Haskell值,因此您可以使用循环来构建将在不执行输出的情况下打印输出的操作:

loop :: (Int, IO ()) -> IO ()
loop (nCase, prnAccum) = do
 x <- getLine
 if x == "0"
  then prnAccum
  else do inpLines <- replicateM (read x) getLine 
          let blocks = map read $ words $ unwords inpLines
              prnAccumAndNext = do
                  prnAccum
                  putStr $ "Case " ++ show nCase ++ " : output = "
                  print $ solve $ blockPair blocks
          loop (nCase + 1, prnAccumAndNext)

main = loop (1, return ())

关于上述解决方案的一些评论:

  • prnAccum,打印结果的动作,穿过递归循环调用,就像nCase一样(我将它们打包成一对作为一种风格,但它只会起作用如果它们作为单独的参数传递,则可以。)
  • 请注意更新的操作prnAccumAndNext如何不直接位于主do块中;它在let块中定义。这就解释了为什么它不会在每次迭代时执行,而是仅在循环结束时执行,最后prnAccum执行。
  • 正如luqui所说,我删除了您使用read时使用的类型注释。 replicateM调用的那个肯定不是必需的,另一个不是那么好,只要blockPairInt的列表作为参数,因为它似乎是案件。
  • 挑剔:我删除了分号,因为它们不是必需的。此外,如果arr引用“数组”,它不是一个非常合适的名称(因为它是一个列表,而不是一个数组),所以我冒昧地把它改成更具描述性的东西。 (你可以在K. A. Buhr的回答中找到一些其他有用的技巧和风格调整的想法。)