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.
Related
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.
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.
I'm trying to understand what happens in the following code, the code behaves properly, but I'm trying to understand why.
import Control.Monad.State
import System.IO
import System.Environment
echoArgs :: [String] -> State Int [String]
echoArgs x = loopArgs x >> return x
where loopArgs [] = return ()
loopArgs s#(x':xs') = modify (+1) >> loopArgs xs'
main :: IO ()
main = do
argv <- getArgs
let s = echoArgs argv
mapM_ putStr' (evalState s 0)
putStrLn $ "\nNum Args = " ++ show (execState s 0)
where putStr' x = putStr $ x ++ " "
What I'm not understanding is why the state of the State monad does not get 'reset' with each successive call to loopArgs. Does the state get passed as a variable, with each >> and if so could someone show me how?
Does the state get passed as a variable, with each >> and if so could someone show me how?
It does indeed. It's helpful to look at a toy implementation of the State monad.
newtype State s a = State { runState :: s -> (a,s) }
instance Monad (State s) where
return a = State $ \s -> (a, s)
State act >>= k = State $ \s ->
let (a, s') = act s
in runState (k a) s'
get :: State s s
get = State $ \s -> (s, s)
put :: s -> State s ()
put s = State $ \_ -> ((), s)
modify :: (s -> s) -> State s ()
modify f = get >>= \x -> put (f x)
When you bind using >>= or >> the accumulated state is threaded through as an argument to the function on the right hand side.
When you run execState or evalState it then just extracts either the resulting value or the state from the resulting tuple.
execState :: State s a -> s -> s
execState act = snd . runState act
evalState :: State s a -> s -> a
evalState act = fst . runState act
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!"
Along with the error I'm having, any tips on how terrible what I'm doing is would be appreciated.
So I'll paste the code, it's a bit; but I think it's mostly correct, I just can't get forkFinally to type check...
The error is on the only line that calls forkFinally:
Ambiguous type variable `e0' in the constraint:
(Exception e0) arising from a use of `forkFinally'
Probable fix: add a type signature that fixes these type variable(s)
In a stmt of a 'do' block:
t <- forkFinally (echoHandler a) (exitPool p)
In the expression:
do { a <- accept s;
t <- forkFinally (echoHandler a) (exitPool p);
atomically
$ do { p' <- readTVar p;
writeTVar p (t : p') };
repeatAccept s p }
In an equation for `repeatAccept':
repeatAccept s p
= do { a <- accept s;
t <- forkFinally (echoHandler a) (exitPool p);
atomically
$ do { p' <- readTVar p;
.... };
.... } Failed, modules loaded: none.
Here's the code:
type ConnectionHandler = (Handle, HostName, PortNumber) -> IO ()
type Pool = TVar [ThreadId]
runConn = do
s <- withSocketsDo (listenOn (PortNumber 1234))
p <- atomically (newTVar ([]::[ThreadId]))
t <- forkIO (repeatAccept s p)
repeatUntilExit stdin stdout putChar ""
p' <- atomically (readTVar p)
mapM killThread (t:p')
repeatAccept s p = do
a <- accept s
t <- forkFinally (echoHandler a) (exitPool p) -- Error here, forkIO instead compiles fine.. (and I guess actually should work just fine too?)
atomically $ do
p' <- readTVar p
writeTVar p (t:p')
repeatAccept s p
exitPool :: Pool -> a -> IO ()
exitPool pool = \_ -> do
tid <- myThreadId
atomically $ do
pool' <- readTVar pool
writeTVar pool $ filter (/=tid) pool'
return ()
echoHandler :: ConnectionHandler
echoHandler a#(hdl,_,_) = repeatUntilExit hdl hdl echoToHandleAndStdout ""
where echoToHandleAndStdout x = hPutChar hdl x >> putChar x
repeatUntilExit :: Handle -> Handle -> (Char -> IO ()) -> [Char] -> IO ()
repeatUntilExit hIn hOut f "exit\n" = hPutStrLn hOut "bye\n"
repeatUntilExit hIn hOut f x = hGetChar hIn >>= \c -> f c >> repeatUntilExit hIn hOut f (appendToLastFive c)
where appendToLastFive a = (reverse . (:)a . take 4 . reverse) x
forkFinally :: Exception e => IO a -> (Either e a -> IO ()) -> IO ThreadId
forkFinally action and_then =
mask $ \restore ->
forkIO $ try (restore action) >>= and_then
Type signature for forkFinally in the latest Control.Concurrent:
forkFinally :: IO a -> (Either SomeException a -> IO ()) -> IO ThreadId
Type signature for forkFinally in your code:
forkFinally :: Exception e => IO a -> (Either e a -> IO ()) -> IO ThreadId
You have tried to generalise the exception type. This isn't a problem if the exception type can be deduced from forkFinally's second parameter. But this is forkFinally's second parameter:
exitPool p :: a' -> IO ()
The type checker tries to unify Either e a -> IO () with a' -> IO () and ends up not being able to deduce what e is.
General solution: specify an explicit type. e.g.
t <- forkFinally (echoHandler a) (exitPool p :: Either SomeException () -> IO ())
Better specific solution: restore the original type signature to forkFinally. It doesn't seem to make sense for it to only catch a limited set of exceptions.