Passing a function in for processing a CSV file: type error
Problem: Process a CSV file and test a condition on it. Current code simply prints instead of testing for the condition.
Issue: Type inference fails. I do not follow why it fails.
Here's the code, less the import boilerplate.
--------------------------------------------------
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 ()
And here's the error:
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;
.... }
(In the future, please include the import boilerplate.)
Type inference is not failing -- since you're not asking the compiler to do any type inference! However, type-checking is failing. Let's see why.
You claim process_lines :: (String -> b) -> Handle -> IO ()
. Experienced Haskeller's will already be shuddering at this type. Why? This type claims that its first argument can be any function at all which does something to a String
. But this is an odd claim to make, since the return type of this function doesn't appear anywhere else in the type of process_lines
-- meaning, we can call this function, but never use its result! Thanks to laziness, this means that the call will never actually happen.
So it's a weird type. Let's see if we can take the argument above and find out where it fails in your code; that should help point to the problem.
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
Take a look at the line marked HERE
. This is the only occurrence of func
in our implementation. According to the argument above, we can never use the output of func
, yet here we seem to be using the output of func
. What type are we using it at? Well, we're using it at an IO {- something -}
type, since it's in a do
-block; furthermore, since we bind result
and then call show result
, the {- something -}
must be some type that we can call show
on -- that is, a member of the Show
class. So the type of func
is not as unrestricted as String -> b
; it's the more restricted Show b => String -> IO b
. A similar argument applies to process_lines_in_file
, so that its updated type ought to be process_lines_in_file :: Show b => (String -> IO b) -> FilePath -> IO ()
.
(Indeed, if you leave off the type signatures, type inference will infer exactly these types for you.)
Now that process_lines_in_file
demands a function that does IO
, we can no longer pass test_csv_row
as-is. You can choose either to call process_lines_in_file (return . test_csv_row) filename
in main
or to change the implementation of test_csv_row
to call return
(which does the trivial IO action: no input or output, just do a pure computation and pretend it did IO).
With these changes, the code compiles.
精彩评论