applying functor on print - haskell

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.

Related

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.

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.

Understanding `modifyMVar_`

Given:
λ: >let m = newMVar "foo"
λ: >m >>= readMVar
"foo"
I tried to use modifyMVar_:
λ: >:t modifyMVar_
modifyMVar_ :: MVar a -> (a -> IO a) -> IO ()
through:
λ: >m >>= \mvar -> modifyMVar_ mvar (\_ -> return "bar")
But, it doesn't look like it modified m from "foo" to "bar".
λ: >m >>= readMVar
"foo"
What'd I do wrong?
m creates new MVar with "foo" every time it's called. You're modifying one MVar then making a new one and checking that. It is the same problem as seen here Setting off a interval on application launch in a Haskell Servant app with exception that there it was an IORef.
myVar <- m
modifyMVar_ myVar (\_ -> return "bar")
readMVar myVar
This should give you "bar" as expected.

How to use maybe monad inside another monad?

I have this code (inside happstack, but could be just the IO monad):
accountHandler conn = do
sessionId <- optional $ readCookieValue "sessionId"
case sessionId of
Nothing -> seeOther ("/" :: String) $ toResponse ()
Just s -> do
result <- loggedInUserId conn s
case result of
Just userId -> seeOther ("/account/" ++ unUserId userId) $ toResponse ()
Nothing -> seeOther ("/" :: String) $ toResponse ()
I want to remove the nested case statements and write something like:
accountHandler conn = do
let action = do
sessionId <- optional $ readCookieValue "sessionId"
userId <- loggedInUserId conn sessionId
return $ seeOther ("/account/" ++ userId)
maybe (seeOther ("/" :: String)) id action $ toResponse ()
... but userId ends up as a type of Maybe String rather than just String. How can I evaluate the nested do block using the maybe monad? (I would also accept a different refactoring that removes the nested cases.)
UPDATE: Below is a generic, though contrived, version of the same problem:
module Main where
getAnswer expected = do
l <- getLine
if l == expected
then return $ Just l
else return $ Nothing
main = do
a <- getAnswer "a"
case a of
Nothing -> putStrLn "nope"
Just x -> do
b <- getAnswer x
case b of
Nothing -> putStrLn "nope"
Just _ -> putStrLn "correct!"
Ok, with your generic example I could do something with Control¸Monad.Transformers. This allows you to create a stack of monads. You can check it out here: http://hackage.haskell.org/package/transformers-0.3.0.0/docs/Control-Monad-Trans-Maybe.html
You can apply MaybeT to everything of type IO (Maybe a) and then do all the computations in the inner do block and then check for Nothing at the end.
module Main where
import Control.Monad.Trans.Maybe
getAnswer expected = MaybeT $ do
l <- getLine
if l == expected
then return $ Just l
else return $ Nothing
main = do
y <- runMaybeT $ do a <- getAnswer "a"
b <- getAnswer a
return b
case y of Nothing -> putStrLn "failure"
(Just _) -> putStrLn "correct"
Another version using liftIO and the Alternative type class:
module Main where
import Control.Monad.Trans.Maybe
import Control.Monad.IO.Class
import Control.Applicative
getAnswer expected = MaybeT $ do
l <- getLine
if l == expected
then return $ Just l
else return $ Nothing
main = do
_ <- runMaybeT $ do a <- getAnswer "a"
b <- getAnswer a
liftIO $ putStrLn "correct"
<|> do liftIO $ putStrLn "failure"
return ()
But using many lift operations is not very elegant.
I'd like to add to MoFu's answer that once you have MaybeT IO, you can use the full power of its MonadPlus instance. For example, if you need to check that some condition holds, use guard or mfilter. So you can write:
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.Trans
import Control.Monad.Trans.Maybe
getAnswer :: (MonadPlus m, MonadIO m) => String -> m String
getAnswer expected = mfilter (== expected) $ liftIO getLine
It's type is very generic, it works for any monad that is MonadPlus and MonadIO. This is handy if you decide to modify your monad stack later. But we could also use more specific type (MonadIO m) => String -> MaybeT m String.
For extracting a MaybeT IO value from your inner computation I'd suggest to write a variant of fromMaybe for MaybeT:
fromMaybeT :: (Monad m) => m a -> MaybeT m a -> m a
fromMaybeT onFail = maybe onFail return <=< runMaybeT
It extracts the result with runMaybeT. If it's Just, just return it, otherwise run onFail action.
Combined together, we get:
main = fromMaybeT (putStrLn "nope") $ do
a <- getAnswer "a"
b <- getAnswer a
liftIO $ putStrLn "correct!"

No cooperation between readFile & IO monad when programming pointlessly

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.

Resources