Haskell 传入用于处理CSV文件的函数:类型错误

Haskell 传入用于处理CSV文件的函数:类型错误,haskell,Haskell,问题:处理CSV文件并测试其条件。当前代码只是打印,而不是测试条件 问题:类型推断失败。我不明白它为什么失败 这是代码,减去导入样板 -------------------------------------------------- has_empty_string :: [String] -> Bool has_empty_string col = any null col ---------------------------------------- get_hashrow

问题:处理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 ()
--------------------------------------------------
有空字符串::[string]->Bool
有空字符串列=
任何空列
----------------------------------------
get_hashrow::[[String]]->[String]
获取行列表=
--看第5栏
地图(\row->row!!5)页
------------------------------
进程行::(字符串->b)->句柄->IO()
过程线函数inh=do
木卫一()
处理文件func文件名中的行=
不知道
测试\u csv\u行=
具有空字符串(获取哈希行(readCSV行))
----------------------------------------
main::IO()
main=do
[文件名](将来,请包括导入样板文件。)

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

您声明
process\u行::(String->b)->Handle->IO()
。经验丰富的哈斯凯勒已经对这种类型感到不寒而栗。为什么?这种类型声称它的第一个参数可以是对
字符串执行某些操作的任何函数。但这是一个奇怪的说法,因为这个函数的返回类型不会出现在
进程行的类型中的任何其他地方
——这意味着,我们可以调用这个函数,但永远不会使用它的结果!多亏了懒惰,这意味着电话永远不会真正发生

所以这是一种奇怪的类型。让我们看看是否可以接受上面的论点,并找出它在代码中失败的地方;这应该有助于指出问题所在

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
process\u lines func inh=do
INEOFB
;这是更受限制的
showb=>String->iob
。类似的参数适用于\u文件中的
process\u lines\u
,因此其更新类型应该是\u文件中的
process\u lines\u::Show b=>(String->IO b)->FilePath->IO()

(事实上,如果不使用类型签名,类型推断将为您准确推断这些类型。)


既然
process\u line\u在文件中
需要一个执行
IO
的函数,我们就不能再按原样通过
test\u csv\u行
。您可以选择在
main
中调用
process\u lines\u文件名(return.test\u csv\u row)filename
,或者将
test\u csv\u row
的实现更改为调用
return
(执行简单的IO操作:无需输入或输出,只需执行纯计算并假装它执行了IO)

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

(将来,请包括导入样板文件。)

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

您声明
process\u行::(String->b)->Handle->IO()
。经验丰富的哈斯凯勒已经对这种类型感到不寒而栗。为什么?这种类型声称它的第一个参数可以是对
字符串执行某些操作的任何函数。但这是一个奇怪的说法,因为这个函数的返回类型不会出现在
进程行的类型中的任何其他地方
——这意味着,我们可以调用这个函数,但永远不会使用它的结果!多亏了懒惰,这意味着电话永远不会真正发生

所以这是一种奇怪的类型。让我们看看是否可以接受上面的论点,并找出它在代码中失败的地方;这应该有助于指出问题所在

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
process\u lines func inh=do
INEOFB
;这是更受限制的
showb=>String->iob
。类似的参数适用于\u文件中的
process\u lines\u
,因此其更新类型应该是\u文件中的
process\u lines\u::Show b=>(String->IO b)->FilePath->IO()

(事实上,如果不使用类型签名,类型推断将为您准确推断这些类型。)


既然
process\u line\u在文件中
需要一个执行
IO
的函数,我们就不能再按原样通过
test\u csv\u行
。您可以选择在
main
中调用
process\u lines\u文件名(return.test\u csv\u row)filename
,或者将
test\u csv\u row
的实现更改为调用
return
(执行简单的IO操作:无需输入或输出,只需执行纯计算并假装它执行了IO)


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

“您可以选择在主文件中调用进程行(return.test\u csv\u row)文件名,或者将test\u csv\u row的实现更改为调用return”,或者您可以替换
结果好的,我不会100%地关注正在发生的事情。但这不是你的错。:-)
=>
实际上是什么意思?不久前,我试图为它找到一个参考资料,但找不到一个好的描述。我确实发现的一个问题已经散乱成了某种形式的语义符号。@Paul这是一个很大的问题,取决于你对类型类的熟悉程度。也许其中一个教程中的“类型类”章节是一个合适的起点,例如,或者甚至是所有三个多路复用。@Daniel:好的,粗略地说,它声明(或限制)类型类中的成员资格。是吗?“您可以选择调用main中的进程\u行\u文件(return.test\u csv\u row)filename,或者将test\u csv\u row的实现更改为调用return”,或者您可以替换
结果好的,我不会100%地关注正在发生的事情。但这不是你的错。:-)
=>
实际上是什么意思?不久前,我试图为它找到一个参考资料,但找不到一个好的描述。我确实发现的一个问题已经散乱成了某种形式的语义符号。@Paul这是一个很大的问题,取决于你对类型类的熟悉程度。也许是上节课的类型