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

Pau*_*han 1 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 ()
Run Code Online (Sandbox Code Playgroud)

这是错误:

 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;
                 .... }
Run Code Online (Sandbox Code Playgroud)

Dan*_*ner 7

(将来,请包括进口样板.)

类型推断没有失败 - 因为你没有要求编译器做任何类型推断!然而,类型检查失败的.让我们看看为什么.

你声称process_lines :: (String -> b) -> Handle -> IO ().经验丰富的Haskeller's已经在这种类型中颤抖.为什么?这种类型声称它的第一个参数可以是任何对a做某事的函数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
Run Code Online (Sandbox Code Playgroud)

看看标记的线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原样传递.您可以选择打电话process_lines_in_file (return . test_csv_row) filenamemain或者改变的执行test_csv_row调用return(这不平凡IO动作:没有输入或输出,只是做一个纯粹的计算和假装它没有IO).

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

  • "你可以选择在main中调用process_lines_in_file(return.test_csv_row)文件名,或者改变test_csv_row的实现来调用return"或者你可以用`let result = func inpStr`替换`result < - func inpStr`,改变类型适当地然后传入`test_csv_row`不变,这可能会更有意义. (5认同)