No cooperation between readFile & IO monad when programming pointlessly - haskell

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 countInFile1 and countInFile3, since you are composing three things of the form a -> IO b, you are thinking of the so-called Kleisli composition, the <=< 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 you do elsewhere. readFile file (with the parameter) is an IO String, so it can be passed along by >>= or =<< to any String -> IO b. But that isn't as swank as what you intended. readFile just by itself is a FilePath -> IO String so it can be >=>'d with any String -> IO b to make a FilePath -> IO b and so on with a b -> IO c, etc. in your case ending with a FilePath -> IO ()
The second error comes from ghc trying to read =<< readFile, to do so it needs readFile to be m b for some monad m, so it settles on Monad ((->) FilePath) (this would actually make sense with Control.Monad.Instances, but would just delay getting the first error.)
If you add the file parameter to these it would be thus,
countInFile1 w file = (putStrLn <=< present w <=< readFile) file
and it is possible that you are parsing countInFile2 and countInFile0 this way, while construing =<< as <=< when actually they are like so:
countInFile0 w file = putStrLn =<< present w =<< (readFile file)
The difference is the same as that between
f n = (even . (+1) . (*3)) n
or equivalently
f = even . (+1) . (3*)
and on the other hand
f n = even $ (+1) $ 3 * n -- cp. your 0 and 2
If you delete the n from both sides here
f = even $ (+1) $ (3*) -- cp. your 1 and 3
you will get a type error akin to the ones you saw:
No instance for (Integral (a0 -> a0)) arising from a use of `even'
Where you use $ you need the parameter n -- as where you use >>= or =<< you need the parameter file. With ., as with <=<, you don't.

Function application has higher precedence than infix =<< operator.
So f =<< g a is equivalent to f =<< (g a) and not (f =<< g) a.

Related

applying functor on print

I've been trying to print 2 values separately, and I tried this code:
import System.Directory
main = getCurrentDirectory >>= \x -> (print <$> doesFileExist x) >> (print <$> doesDirectoryExist x)
but it doesn't print anything however the following code works fine:
import System.Directory
main = getCurrentDirectory >>= \x -> doesFileExist x >>= print >> doesDirectoryExist x >>= print
any reasons for why the 1st code doesn't print anything ?
If you fmap print over an IO action, you don't get an IO action that performs this printing. You just get an IO action that performs whatever side-effects the original action had, but instead of yielding the printable value as the result it yields another IO action as the result which you could then execute in a separate step:
import Control.Applicative
import Data.Time
printCurrentTime :: IO ()
printCurrentTime = do
tPrinter <- print <$> getCurrentTime
tPrinter
or, without do notation,
printCurrentTime = print <$> getCurrentTime >>= \tPrinter -> tPrinter
In other words,
printCurrentTime = print <$> getCurrentTime >>= id
By the monad laws, f <$> a >>= b is the same as a >>= b . f, i.e.
printCurrentTime = getCurrentTime >>= id . print
which is the same as simply
printCurrentTime = getCurrentTime >>= print
That could than be written with do notation as
printCurrentTime = do
t <- getCurrentTime
print t
As the comment states, you get an IO (IO ()). We can use join to get rid of the duplicate monad.
join (print <$> doesFileExist x)
But "fmap and then join" is literally the definition of >>= (join and >>= can be mutually defined in terms of each other). That's why your >>= works.
In the first item you use a functor mapping, you thus create for
print <$> doesFileExist x :: IO (IO ())
Indeed, doesFileExist :: FilePath -> IO Bool will return an IO Bool. Now what you do is perform a functor mapping, so you will map the Bool outcome to an IO (), and thus we now have an IO (IO ()). This IO function will not print anything, since the IO () is the "result" of the IO calculations, not an action.
You thus should use:
doesFileExist x >>= print
since this will work on the result of doesFileExist, and evaluate to an IO () where it will print the Boolean.

Point free version for readMaybe

I want to write a function to read an Int without do notation. It works (see below), but I was wondering if it the bit around readMaybe can be written in point free form (or cleaned up a bit in some other way)?
main :: IO ()
main = getLine >>= (\x -> return $ (readMaybe x :: Maybe Int)) >>= print
Step 1: Replace the lambda with its pointfree equivalent:
main :: IO ()
main = getLine >>= return . (readMaybe :: String -> Maybe Int) >>= print
Step 2: Replace m >>= return . f with f <$> m:
main :: IO ()
main = (readMaybe :: String -> Maybe Int) <$> getLine >>= print
Step 3: Replace f <$> m >>= g with m >>= g . f:
main :: IO ()
main = getLine >>= print . (readMaybe :: String -> Maybe Int)
Step 4: Use a type application instead of writing out a long, awkward type:
{-# LANGUAGE TypeApplications #-}
main :: IO ()
main = getLine >>= print . readMaybe #Int
As an alternative to using <$> in steps 2 and 3, you can accomplish the same with just the monad laws, like this (picking up after step 1):
Replace m >>= f >>= g with m >>= \x -> f x >>= g (associativity):
main :: IO ()
main = getLine >>= \x -> (return . (readMaybe :: String -> Maybe Int)) x >>= print
Simplify the . away:
main :: IO ()
main = getLine >>= \x -> return ((readMaybe :: String -> Maybe Int) x) >>= print
Replace return x >>= f with f x (left identity):
main :: IO ()
main = getLine >>= \x -> print ((readMaybe :: String -> Maybe Int) x)
Now just replace that new lambda with its pointfree equivalent, and you end up in the exact same place as step 3.

optparse-applicative with custom monad

I'm trying to use my own monad (instead of IO) with customExecParser https://hackage.haskell.org/package/optparse-applicative-0.15.1.0/docs/Options-Applicative-Extra.html#v:customExecParser.
So I've ended up with (significant function being fff):
data MoscConfig = MoscConfig {
datadir :: FilePath
, config :: FilePath
, pendingPath :: FilePath
, socket :: FilePath
}
type Mosco = StateT MoscConfig IO
main :: IO ()
main = join . customExecParser (prefs showHelpOnError) $
info (helper <*> parser)
( fullDesc
)
fff :: (a1 -> StateT MoscConfig IO a2) -> a1 -> IO a2
fff f = (flip evalStateT (MoscConfig "" "" "" "")) . f
xyzz :: Text -> Mosco ()
xyzz x = do
liftIO $ print x
liftIO $ print "testabcxyz"
xyzz' :: Text -> Text -> Mosco ()
xyzz' x x' = do
liftIO $ print x
liftIO $ print x'
liftIO $ print "testabcxyz"
parser :: Parser (IO ())
parser = do
fff xyzz <$> textOption ( long "zzz" )
<|>
((fmap fff) xyzz')
<$> textOption ( long "zzz" )
<*> textOption ( long "zzz" )
However, the only disadvantage with the above approach is needing to fmap the required number of times (matching the function arguments in xyzz or xyzz). I do recall running into this type of problem before. Is there some way I can avoid this (and just have a single function needing to be called)?
Ideally I'd hope to have a monad transformer for this but unfortunately this seems to be implemented to IO only.
I think this boils down to the question: is there a function fff that can be applied to both of:
xyzz :: a -> r
xyzz' :: a -> b -> r
so that:
fff xyzz :: a -> r'
fff xyzz' :: a -> b -> r'
And the answer is "no", at least not without some type class trickery that isn't worth considering.
Instead, assuming your real version of fff doesn't actually do anything with f except compose with it, I guess I would consider writing:
fff :: Parser (Mosco a) -> Parser (IO a)
fff = fmap $ flip evalStateT (MoscConfig "" "" "" "")
parser :: Parser (IO ())
parser = fff (xyzz <$> textOption ( long "zzz" ))
<|> fff (xyzz' <$> textOption ( long "zzz" ) <*> textOption ( long "zzz" ))
This whole approach seems a little "off", though. Do you really need a MoscConfig available while parsing options? Unless you have a really complicated options parsing problem on your hands, it would be more usual to parse the options directly into an intermediate data structure and then run your Mosco actions against that data structure to modify a MoscConfig state and do IO and so on.
In terms of what I wanted to achieve (being able to just pass parameters to function within the Mosco monad context -
moscparams ::
Maybe Text
-> Maybe Text
-> Maybe Text
-> Maybe Text
-> Mosco a -> IO a
moscparams dd c pp sp x = do
ddd <- crFile
cd <- pure "not used"
ppd <- crDirPending
spd <- socketFile
evalStateT x
$ MoscConfig
(maybe ddd cs dd)
(maybe cd cs c)
(maybe ppd cs pp)
(maybe spd cs sp)
moscF' :: Text -> Text -> Mosco ()
moscF' x x' = do
liftIO $ print x
liftIO $ print x'
liftIO $ print "testabcxyz"
moscparams' :: Parser (Mosco ()) -> Parser (IO ())
moscparams' x = moscparams
<$> optional (textOption ( long "data-dir" ))
<*> optional (textOption ( long "config-path" ))
<*> optional (textOption ( long "pending-path" ))
<*> optional (textOption ( long "socket-path" ))
<*> x
parser :: Parser (IO ())
parser = do
moscparams'
(( moscF')
<$> textOption ( long "example-param-1" )
<*> textOption ( long "example-param-2" )
)

Why doesn't this simple composition work?

I was recently in need of putting head in between two monadic operations. Here's the SSCCE:
module Main where
f :: IO [Int]
f = return [1..5]
g :: Int -> IO ()
g = print
main = do
putStrLn "g <$> head <$> f"
g <$> head <$> f
putStrLn "g . head <$> f"
g . head <$> f
putStrLn "head <$> f >>= g"
head <$> f >>= g
This program is well-formed and compiles without warnings. However, only one version out of 3 above works1. Why is that?
And specifically, what would be the best way to link f and g together with head in the middle? I ended up using the 3rd one (in the form of do notation), but I don't really like it, since it should be a trivial one-liner2.
1 Spoiler alert: the 3rd one is the only one that prints 1; the other two are silent, both under runhaskell and repl.
2 I do realize that those are all one-liners, but the order of operations feels really confusing in the only one that works.
Probably the best way to write this is:
f >>= g . head
or in a more verbose form:
f >>= (g . head)
so we basically perform an fmap on the value for f (we thus take the head of the values wrapped in the IO monad), and then we pass then to g, like:
(head <$> f) >>= g
is semantically the same.
But now what happens if we use g <$> head <$> f? Let us first analyze the types:
f :: IO [Int]
g :: Int -> IO ()
(<$>) :: Functor m => (a -> b) -> m a -> m b
(I used m here to avoid confusion with the f function)
The canonical form of this is:
((<$>) ((<$>) g head) f)
The second (<$>) takes a g :: Int -> IO () and head :: [c] -> c as parameters, so that means that a ~ Int, b ~ IO (), and m ~ (->) [c]. So the result is:
(<$>) g head :: (->) [c] (IO ())
or less verbose:
g <$> head :: [c] -> IO ()
The first (<$>) function thus takes as parameters g <$> head :: [c] -> IO (), and IO [Int], so that means that m ~ IO, a ~ [Int], c ~ Int, b ~ IO (), and hence we obtain the type:
(<$>) (g <$> head) f :: IO (IO ())
We thus do not perform any real action: we fmap the [Int] list to an IO action (that is wrapped in the IO). You could see it as return (print 1): you do not "evaluate" the print 1, but you return that wrapped in an IO.
You can of course "absorb" the outer IO here, and then use the inner IO, like:
evalIO :: IO (IO f) -> IO f
evalIO res = do
f <- res
f
or shorter:
evalIO :: IO (IO f) -> IO f
evalIO res = res >>= id
(this can be generalized to all sorts of Monads, but this is irrelevant here).
The evalIO is also known as join :: Monad m => m (m a) -> m a.
The first and second are exactly the same, because <$> is left-associative and head is a function, and <$> is . in the function monad. Then,
g . head <$> f
= fmap (print . head) (return [1..5] :: IO [Int])
= do { x <- (return [1..5] :: IO [Int])
; return ( print (head x) ) }
= do { let x = [1..5]
; return ( print (head x) ) } :: IO _whatever
=
return ( print 1 ) :: IO (IO ())
We have one too many returns there. In fact,
= fmap (print . head) (return [1..5] :: IO [Int])
= return (print (head [1..5]))
= return (print 1)
is a shorter derivation.
The third one is
(head <$> f) >>= g
= (fmap head $ return [1..5]) >>= print
= (return (head [1..5])) >>= print
= (return 1) >>= print
which is obviously OK.

fmap versus <$>

According to the documentation <$> is an synonym for fmap and they have the following types:
(<$>) :: Functor f => (a -> b) -> f a -> f b
fmap :: Functor f => (a -> b) -> f a -> f b
So it seems to me, from the signatures above, that they take the arguments in the same order, the only difference being that one is infix and the other is not. I have two pieces of code, one using fmap, and the other using <$>. Why is it that only the former runs correctly?
import Control.Applicative
main :: IO ()
main = do
[x, y] <- map read . words <$> getLine
putStrLn $ show (x + y)
This one won't compile:
import Control.Applicative
main :: IO ()
main = do
[x, y] <- map read . fmap words getLine
putStrLn $ show (x + y)
Precedence of operators is expressed as an integer between 0 and 9, while function application effectively has precedence 10 (higher than any operator).
(.) has very high precedence (9), while (<$>) has lower precedence (4), resulting in your first expression being parsed as
((map read) . words) <$> getLine
while your second expression is parsed as
(map read) . (fmap words getLine)
resulting in an attempt to compose an IO [String] value with a function of type [String] -> [a].
This is due to operator precedence. If we look at the source code, we see that:
infixl 4 <$>
infixr 9 .
So that means that if you write:
map read . words <$> getLine
Haskell sees this as:
(map read . words) <$> getLine
But if you write:
map read . fmap words getLine
Haskell sees this as:
(map read) . (fmap words getLine)
So the arguments of fmap are different.
If we however add brackets, the two will be equivalent:
import Control.Applicative
main :: IO ()
main = do
[x, y] <- map read . (words <$> getLine)
putStrLn $ show (x + y)

Resources