问题:处理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;
.... }
答案 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)。
通过这些更改,代码可以编译。