2011-09-06 12 views
1

問題:處理CSV文件並測試一個條件。當前代碼只是打印而不是測試條件。傳遞函數以處理CSV文件:鍵入錯誤

問題:類型推斷失敗。我不追蹤它爲什麼失敗。

下面是代碼,少了導入樣板。

-------------------------------------------------- 
has_empty_string :: [String] -> Bool 
has_empty_string col = 
    any null col 

---------------------------------------- 
get_hashrow :: [[String]] -> [String] 
get_hashrow sheet = 
    -- looking at column 5 
    map (\row -> row !! 5) sheet 

------------------------------ 
process_lines :: (String -> b) -> Handle -> IO() 
process_lines func inh = do 
    ineof <- hIsEOF inh 
    if ineof 
     then return() 
     else do inpStr <- hGetLine inh 
       result <- func inpStr 
       putStrLn $ show result 
       process_lines func inh 


------------------------------ 
process_lines_in_file :: (String -> b) -> FilePath -> IO() 
process_lines_in_file func filename = 
    do inh <- openFile filename ReadMode 
     process_lines func inh 

---------------------------------------- 
test_csv_row :: String -> Bool 
test_csv_row row = 
    has_empty_string (get_hashrow (readCSV row)) 

---------------------------------------- 
main :: IO() 
main = do 
    [filename] <- getArgs 
    process_lines_in_file test_csv_row filename 
    return() 

而這裏的錯誤:

Couldn't match expected type `b' against inferred type `IO a' 
     `b' is a rigid type variable bound by 
      the type signature for `process_lines' at content-hash-p.hs:29:28 
    In a stmt of a 'do' expression: result <- func inpStr 
    In the expression: 
     do { inpStr <- hGetLine inh; 
      result <- func inpStr; 
       putStrLn $ show result; 
      process_lines func inh } 
    In the expression: 
     if ineof then 
      return() 
     else 
      do { inpStr <- hGetLine inh; 
       result <- func inpStr; 
        putStrLn $ show result; 
       .... } 

回答

7

(在未來,請包括進口樣板。)

類型推斷沒有失敗 - 因爲你不是要求編譯器做任何類型推斷!但是,類型檢查失敗。讓我們看看爲什麼。

您聲明process_lines :: (String -> b) -> Handle -> IO()。有經驗的哈斯克勒已經在這種類型中發抖了。爲什麼?這種類型聲稱它的第一個參數可以是的任何函數,它對String做某事。但這是一個奇怪的說法,因爲這個函數的返回類型不會出現在process_lines類型的任何其他地方 - 也就是說,我們可以調用這個函數,但從不使用它的結果!由於懶惰,這意味着電話將永遠不會發生。

所以這是一個奇怪的類型。讓我們看看我們是否可以採用上面的參數並找出代碼中的失敗位置;這應該有助於指出問題。

process_lines func inh = do 
    ineof <- hIsEOF inh 
    if ineof 
     then return() 
     else do inpStr <- hGetLine inh 
       result <- func inpStr -- HERE 
       putStrLn $ show result 
       process_lines func inh 

看一下標記爲HERE的行。這是我們實施中唯一發生的func。根據上面的論點,我們不能使用func的輸出,但在這裏我們似乎正在使用func的輸出。我們使用什麼類型的?那麼,我們使用IO {- something -}類型,因爲它在do - 塊;此外,由於我們綁定了result,然後致電show result,因此{- something -}必須是某種類型,我們可以在show之上 - 即Show類的成員。所以func的類型不像String -> b那樣不受限制;這是更受限制的Show b => String -> IO b。類似的論點適用於process_lines_in_file,所以它的更新類型應該是process_lines_in_file :: Show b => (String -> IO b) -> FilePath -> IO()

(事實上,如果你省略的類型簽名,類型推斷將推斷正是這些類型你。)

現在process_lines_in_file要求,做IO的功能,我們不能再通過test_csv_row原樣是。您可以選擇在main中調用process_lines_in_file (return . test_csv_row) filename或將test_csv_row的實現更改爲調用return(它執行平凡的IO操作:無輸入或輸出,只需執行純計算並假裝它爲IO)。

隨着這些變化,代碼編譯。

+5

「您可以選擇調用process_lines_in_file(返回。test_csv_row)filename或更改test_csv_row的實現以調用返回「或者,您可以用'let result = func inpStr'替換result < - func inpStr',相應地更改類型,然後傳遞'test_csv_row',其中可能會更有意義 – sepp2k

+0

好吧,我沒有按照100%進行下一步操作,但這並不是你的錯。:-)'=>'實際上是什麼意思?我試着爲它找到一個參考,以及無法挖掘出一個好的描述,我找到了一個正式的語義符號 –

+0

@Paul這是一個很大的問題,這取決於你對類型類的使用是多麼的舒適。教程將是一個合適的起點,例如http://learnyouahaskell.com/types-and-typeclasses或http://book.realworldhaskell.org/read/using-typeclasses.html或http://www.haskell。 org/tutorial/classes.html甚至全部三個複用。 –