我编写了一个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
有谁知道如何做到这一点?另外,如果可能的话,你可以建议我在最后打印输出线吗?
提前致谢。
答案 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
执行。read
时使用的类型注释。 replicateM
调用的那个肯定不是必需的,另一个不是那么好,只要blockPair
将Int
的列表作为参数,因为它似乎是案件。arr
引用“数组”,它不是一个非常合适的名称(因为它是一个列表,而不是一个数组),所以我冒昧地把它改成更具描述性的东西。 (你可以在K. A. Buhr的回答中找到一些其他有用的技巧和风格调整的想法。)