No collaboration between readFile & IO monad when programming is pointless

Why countInFile1 and countInFile3 have compiler errors when countInFile0 and countInFile2 do not. All four are one and the same.

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 wf = 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 wf = 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 countInFile3 has 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 
+4
source share
2 answers

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.

+9
source

A functional application takes precedence over the infix =<< operator.

So f =<< ga equivalent to f =<< (ga) , not (f =<< g) a .

+8
source

Source: https://habr.com/ru/post/1434751/


All Articles