传递函数以处理CSV文件:输入错误

时间:2011-09-06 17:23:16

标签: haskell

问题:处理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;
                 .... }

1 个答案:

答案 0 :(得分:7)

(将来请包含导入样板。)

类型推断没有失败 - 因为您没有要求编译器进行任何类型推断!但是,类型检查 失败。让我们看看为什么。

您声称process_lines :: (String -> b) -> Handle -> IO ()。经验丰富的Haskeller's已经在这种类型中颤抖。为什么?此类型声称其第一个参数可以是任何函数,它对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的成员1}}类。因此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了。您可以选择在process_lines_in_file (return . test_csv_row) filename中调用main或将test_csv_row的实现更改为调用return(执行简单的IO操作:无输入或输出,只需执行一个纯粹的计算并假装它做了IO)。

通过这些更改,代码可以编译。