When using countInFile1 and countInFile3 , since you compose three things in the form a -> IO b , you think of the so-called Claysley composition, <=< from Control.Monad . Try
countInFile1 w = putStrLn <=< present w <=< readFile countInFile3 w = putStrLn <=< return . show . count w <=< readFile
Or you can write countInFile3 w file = ... =<< readFile file , as in other places. readFile file (with parameter) is an IO String , so it can be passed by >>= or =<< to any String -> IO b . But it is not as wide as you expected. readFile itself is a FilePath -> IO String , so for etc.>
The second error comes from ghc trying to read =<< readFile , it requires readFile be mb for some monad m, so it settles to Monad ((->) FilePath) (it really makes sense with Control.Monad.Instances , but will just delay getting the first error.)
If you add the file parameter to it, it will be this way
countInFile1 w file = (putStrLn <=< present w <=< readFile) file
and itβs possible that you parse countInFile2 and countInFile0 in this way, creating =<< as <=< , when in fact they look like this:
countInFile0 w file = putStrLn =<< present w =<< (readFile file)
The difference is the difference between
fn = (even . (+1) . (*3)) n
or equivalent
f = even . (+1) . (3*)
and on the other hand
fn = even $ (+1) $ 3 * n -- cp. your 0 and 2
If you remove n on both sides here
f = even $ (+1) $ (3*) -- cp. your 1 and 3
you will get a type error close to the ones you saw:
No instance for (Integral (a0 -> a0)) arising from a use of `even'
If you use $ , you need parameter n - as used >>= or =<< you need parameter file . S , as with <=< , you do not.