applying functor on print

Viewed 97

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 ?

3 Answers

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.

Related