2016-12-01 36 views
0

我已經寫了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 

有誰知道如何可以做到這一點?另外,如果可能的話,你能否建議我在最後打印輸出行?

在此先感謝。

+1

「另外,如果可能,你能否建議我在最後打印輸出行的方法? - 我不知道你還想打印什麼,在哪一點上它應該發生.. – duplode

+0

@duplode,它應該像 - 開始時的所有輸入一樣運行,然後在用戶輸入0之後,它應該打印輸出。 – user7201762

+0

我需要一些幫助 – user7201762

回答

4

對於問題的第一部分,當前案例編號是您在程序執行過程中想要維護的某個「狀態」的示例。在其他語言中,毫無疑問,您會使用可變變量。

在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 woul ð看起來像這樣:

main = do 
    blocks <- readBlocks 
    putStr $ unlines $ 
    zipWith (\n line -> "Case " ++ show n ++ ": " ++ line) 
      [1..] (map (show . solve . blockPair) blocks) 
+0

謝謝,你的第一個竅門奏效了。但關於第二個,我有一個類似的函數,終止於0輸入,但我如何控制傳遞給我的輸出函數的參數?你的代碼將把每一行處理爲一個單獨的參數,這不是我想要的。無論如何,謝謝你的嘗試。 – user7201762

+1

是的,現在你的方法更清晰了。這正是我想要的。我猜這個問題現在已經解決了。非常感謝。 – user7201762

+0

@ user7201762,如果這個答案有竅門,您可以點擊答案頂部的複選標記將其標記爲「接受答案」。 – luqui

1

這是精神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作爲參數列表,因爲它似乎是這種情況。
  • Nitpicking:我刪除了分號,因爲它們不是必需的。另外,如果arr引用「數組」,它不是一個非常合適的名稱(因爲它是一個列表,而不是一個數組),所以我冒昧地將其改爲更具描述性的內容。 (你可以在K. A. Buhr的答案中找到一些有用的技巧和風格調整的其他想法。)