2013-11-09 70 views
2

我有一個程序需要一些命令行參數。從Haskell的命令行參數解析CSV列表

說第一個命令行參數是逗號分隔值(CSV)整數列表。

我想將第一個參數"1,2,4,8,16"轉換爲[1,2,4,8,16]。我試圖解析字符串到一個Int列表,但我有一個編譯錯誤。

Haskell代碼:

import System.Environment 
import Data.List 
import Text.Regex 

main = do 
    args <- getArgs 

    ints <- if (length args > 1) 
      then (mapM read (splitRegex (mkRegex ",") (args!!1))) 
      else [1,3,5] -- defaults 
    print (ints) 

編譯錯誤:

myProg.hs:10:16: 
    Couldn't match expected type `IO' with actual type `[]' 
    In the expression: [1, 3, 5] 
    In a stmt of a 'do' block: 
     ints <- if (length args > 1) then 
        (mapM read (splitRegex (mkRegex ",") (args !! 1))) 
       else 
        [1, 3, 5] 
    In the expression: 
     do { args <- getArgs; 
      ints <- if (length args > 1) then 
         (mapM read (splitRegex (mkRegex ",") (args !! 1))) 
        else 
         [1, ....]; 
      print (ints) } 

我不能確定什麼這種類型的錯誤表示。如果有人能夠向我解釋類型錯誤以及如何修改我的代碼以實現預期結果,我將不勝感激。

+0

我建議使用木薯解析CSV,而不是正則表達式。不是你知道的問題的答案,但可能是這項工作的正確工具。 – idontgetoutmuch

回答

3

您不想使用<-來定義ints,因爲您沒有在那裏執行IO操作。你可以使用一個let綁定。這也可以讓您用普通的map代替mapM的呼叫。

第一個正確的參數也被索引爲0,而不是像你可能在C中看到的那樣。您可以使用head來獲得該值。

let ints = if length args >= 1 
      then map read (splitRegex (mkRegex ",") (head args)) 
      else [1, 3, 5] 
2

表達

if (length args > 1) 
then (mapM read (splitRegex (mkRegex ",") (args!!1))) 
else [1,3,5] -- defaults 

病類型化,因爲這兩種情況(當時,其他人)的值不相符。類型MAPM的是

mapM :: Monad m => (a -> m b) -> [a] -> m [b] 

所以然後分支的類型米並[b]對於一些單子米(在這種情況下,IO)。然而,else分支只是一個數字列表。您可以通過編寫

return [1,3,5] 

爲其他情況,使其類型爲IO [Int]。

但這可能不是最好的前進方向。你的分支有問題;函數read不會返回IO中的值,因此它不適合作爲mapM的第一個參數。事實上,沒有理由在IO中進行這種計算,因爲ints的值是作爲參數(args)的純函數獲得的。我建議的主要外側

extractInts :: [String] -> [Int] 

類型實現它,作爲一個函數,那麼你可以把它工作到主像這樣:

main = do 
    args <- getArgs 
    let ints = extractInts args 
    print ints