Why do countInFile1 & countInFile3 have compiler errors, when countInFile0 & countInFile2 do not. All four are the same thing.
count :: String -> String -> Int
count w = length . filter (==w) . words
present :: String -> String -> IO String
present w = return . show . count w
-- VALID: pointed readFile, regular present
countInFile0 :: String -> FilePath -> IO ()
countInFile0 w f = putStrLn =<< present w =<< readFile f
-- INVALID: pointless readFile, regular present
countInFile1 :: String -> FilePath -> IO ()
countInFile1 w = putStrLn =<< present w =<< readFile
-- VALID: pointed readFile, inline present
countInFile2 :: String -> FilePath -> IO ()
countInFile2 w f = putStrLn =<< (return . show . count w) =<< readFile f
-- INVALID: pointless readFile, inline present
countInFile3 :: String -> FilePath -> IO ()
countInFile3 w = putStrLn =<< (return . show . count w) =<< readFile
main = do
countInFile0 "bulldogs" "bulldogs.txt"
countInFile1 "bulldogs" "bulldogs.txt"
countInFile2 "bulldogs" "bulldogs.txt"
countInFile3 "bulldogs" "bulldogs.txt"
Also why does countInFile3 have this additional error that countInFile1 does not:
example_one.hs:21:27:
No instance for (Monad ((->) FilePath))
arising from a use of `=<<'
Possible fix:
add an instance declaration for (Monad ((->) FilePath))
In the expression:
putStrLn =<< (return . show . count w) =<< readFile
In an equation for `countInFile3':
countInFile3 w
= putStrLn =<< (return . show . count w) =<< readFile
With both
countInFile1andcountInFile3, since you are composing three things of the forma -> IO b, you are thinking of the so-called Kleisli composition, the<=<fromControl.Monad. TryOr you can write
countInFile3 w file = ... =<< readFile file, as you do elsewhere.readFile file(with the parameter) is anIO String, so it can be passed along by>>=or=<<to anyString -> IO b. But that isn’t as swank as what you intended.readFilejust by itself is aFilePath -> IO Stringso it can be>=>‘d with anyString -> IO bto make aFilePath -> IO band so on with ab -> IO c, etc. in your case ending with aFilePath -> IO ()The second error comes from ghc trying to read
=<< readFile, to do so it needsreadFileto be m b for some monad m, so it settles onMonad ((->) FilePath)(this would actually make sense withControl.Monad.Instances, but would just delay getting the first error.)If you add the
fileparameter to these it would be thus,and it is possible that you are parsing
countInFile2andcountInFile0this way, while construing=<<as<=<when actually they are like so:The difference is the same as that between
or equivalently
and on the other hand
If you delete the
nfrom both sides hereyou will get a type error akin to the ones you saw:
Where you use
$you need the parametern— as where you use>>=or=<<you need the parameterfile. With., as with<=<, you don’t.